I am creating a WinForms application (for an instrumentation system) where the main form displays a list of equipment in a tableLayoutPanel wrapped in a groupBox. Each item has an associated label and comboBox. The application must populate the list of equipment at runtime, and then the user will select a value for each comboBox, which the application will fetch to run tests.
Here is a partial screenshot of what I'm describing:
I would like to make a class to hold the list of items, the possible options for the associated comboBox, and the user's selection and then data bind it such that changes to the class cause the correct controls to be created and populated. But I'm not sure if this is possible, and if it is, how I'd set up the binding sources?
Per this example, this is the class I think I should start with:
public class TestEquipment
{
public string Name { get; set; }
public List<string> Options { get; set; }
public string Selection { get; set; }
public TestEquipment(string name, string selection)
{
Name = name;
Selection = selection;
}
}
Related
I have a simple POCO data structure with what I believe is the correct implementation of loading a list of children in a 'Lazy' manner.
Something like this:
public class Parents
{
public Guid ID { get; set; }
public string Name { get; set; }
//children
private List<Children> childrenList;
public List<Children> ChildrenList
{
get
{
if (childrenList == null) { childrenList = Children.FindByParentID(ID); }
return childrenList;
}
set childrenList = value;
}
}
I need to use a DevExpress XtraGrid control to present the data as it is the control set used by my employer.
I bind the List<Parents> to the grid (e.g. myGrid.DataSource = Parents.FindAll(); ) and everything is fine until I try to expand the first child list using the "+" expansion indicator on the grid.
After I try to expand the first item, the grid (I'm assuming) goes through every parent and tries to load the child list resulting in very slow performance. I can see this while debugging.
I would like the grid to only load the child list for the single item requested. Any ideas about how to achieve this behavior would be very much appreciated.
I am new to .net core - have been using aspx web pages and .net framework 4.x for a number of years. I have a project where we want to display different controls (textbox, dropdown, checkbox) on the page based on values returned from a query. For example, user chooses "A" from a dropdown list and it shows 10 controls, if they choose object B it shows 8 controls, etc. Previously in .net framework, I would use a content placeholder with an ID and then find that ID and start adding controls (controls.Add(newControl)) in the placeholder. It doesn't seem that is an option with .net core. It seems like this would be a common need for various web applications, but I'm not finding many hits.
Another question is whether this can be done in the code behind or if it has to be done on the client-side. If one of the controls in the list is a dropdown, there will be a query that a subroutine will run to get the Key/Value pairs for the dropdown. To me this means it would be more effective on the server side.
I haven't really found any good examples when I do some searching. Can anyone point me to a good resource or provide me with a basic example - either client-side or server-side? Thanks!
There are many options, but I'll describe a simple one, using server side processing. As you explained in your comment, there will be 2 pages:
One that will display the select element that will be used to choose a set of controls.
The page that will be returned according to the previous choise, displaying the selected set of controls.
I assume that you know how to build the first page.
For the second page, you can leverage the ASP.NET Core MVC pattern to achieve the desired result.
You will need the three usual MVC elements:
An Action in a Controler.
A ViewModel for your Razor View.
A Razor View.
The Action does the following:
Receives the id of the selected set of control (via the Action's parameter).
Uses this id to retrieve the information about the corresponding set of controls from your repository.
Builds a ViewModel out of the received information.
Builds a View using the obtained ViewModel.
Return the builded View.
Here is some simplified example code:
In your controller, add the following method:
#!lang-cs
Public IActionResult GetProgramControlSet(int ProgramId)
{
// Here, use the id to get the data from your repository
// that will be used to build set of controls.
// Supposing you have defined a GetControls method,
// it could look like:
var SelectedControls = MyRepository.GetControls(ProgramId);
// If needed, you can build a ViewModel out of the received SelectedControls.
var SelectedControlsViewModel = new ControlSetViewModel(SelectedControls);
return View(SelectedControlsViewModel)
}
Of course, many things are missing here: error handling, etc...
Here is what the ViewModel could be:
#!lang-cs
public class ControlSetViewModel
{
public string Name { get; private set; }
public List<IControl> Controls { get; private set; }
public ControlSetViewModel(...)
{
// Whatever needs to be done to construct the ViewModel
}
}
public enum ControlKind
{
Button,
Select,
Textarea
//...
}
public interface IControl
{
ControlKind Kind { get; }
}
public class ControlButton : IControl
{
public ControlKind Kind => ControlKind.Button;
public string Label { get; set; }
public string Text { get; set; }
public string Color { get; set; }
// ... All other needed properties for the button
}
public class ControlTextarea : IControl
{
public ControlKind Kind => ControlKind.Textarea;
public string Label { get; set; }
public string PlaceholderText { get; set; }
public string RowCount { get; set; }
// ... All other needed properties for the textarea
}
public class ControlSelect : IControl
{
public ControlKind Kind => ControlKind.Select;
public string Label { get; set; }
public string PlaceholderText { get; set; }
public List<SelectOption> Options { get; set; }
// ... All other needed properties for the select
}
public class SelectOption
{
public string Text { get; set; }
public string Value { get; set; }
}
You could also use inheritance instead of interface for the control classes.
Now the view.
It is a Razor page containing something akin to
#model ControlSetViewModel
#*... some HTML ...*#
<div>
<h1>#Model.Name</h1>
#foreach(var control in Model.Controls)
{
<div>
switch(control.GetControlKind())
{
case ControlKind.TextArea:
var Textarea = (ControlTextarea)control;
<label>#Textarea.Label</label>
<textarea rows="#Textarea.RowCount"/>
break;
case ControlKind.Select:
var Select = (ControlSelect)control;
<label>#Select.Label</label>
<select>
#foreach(var option in Select.Options)
{
<option value="#option.Value">#option.Text</option>
}
</select>
break;
#*... etc ...*#
default:
#*... etc ...*#
}
</div>
}
</div>
#*... More HTML ...*#
Of course this is far to be finished. All the infrastructure and code that will actually react to the displayed controls is missing.
Is it a form you that will be posted?
Is it Javascript code that will react to the control manipulation?
Or another mecanism?
This questions will need to be addressed.
I want to have a container of objects that will be visualised in WinForms' DataGridView control.
As far as I know, I can bind a container to DataGridView via the DataSource property.
But I wonder, is there any way to do it in Designer? I see a lot of options related to that (like DataSource, DataMember etc) but I don't see any option that will give me a possibility to choose my own container inside the Form class.
I don't want to make this kind of stuff programmatically if it's available in the designer.
DataSource is bindable in designer. You can press the little arrow at the top of the DataGridView, and Choose Data Source. At the bottom> Add Project DataSource...
After adding the class, that will contain Your DataSource, You can set in the properties pane which public property is Your DataSource.
For example:
public class ThereIsDataSourceInThisClass
{
public ThereIsDataSourceInThisClass()
{
MyDataSource = new BindingList<Thing>();
MyDataSource.Add(new Thing { First = "aa", Second = "bb" });
}
public BindingList<Thing> MyDataSource { get; set; }
public class Thing
{
public string First { get; set; }
public string Second { get; set; }
}
}
I selected ThereIsDataSourceInThisClass in the wizard, than I selected MyDataSource in the DataSource property.
The result is>
I have a combobox which is structured like this:
public class PersonDataQueryField
{
public string FriendlyName { get; set; }
public IList<string> XPaths { get; set; }
public Type DataType { get; set; }
}
A list of this class exist in my ViewModel, and bound to a Combobox, with the DisplayMemeberPath=FriendlyName. I have several DataTemplates in my View, which will trigger based upon the selected DataType in the Combobox to fill the ContentControl. To the right of this combobox a TextBox exist where the user can enter a SearchQuery. The Text property is of type object and meant to be casted to the SelectedPersonDataQueryField.DataType when the user presses "Search".
var searchQuery = (SelectedSearchQueryParameter.DataType) SearchQuery;
This is not allowed since SelectedSearchQueryParameter is a Property and not a Type, but the DataType is Type. How can I achieve this?
I'd agree with Jon. Though, this is how:
dynamic searchQuery = Convert.ChangeType(SearchQuery,
SelectedSearchQueryParameter.DataType);
but why, and what's next :p?
If having a List filled with objects of the following type:
public class Person {
public string Name { get; set; }
public string Ssn { get; set; }
}
How can one set the value of the property Name to be what's beeing displayed within an ASP.NET DropDown, without setting any properties on the ASP.NET DropDown object? Of course, one way would be to ovveride ToString() on the class Person, but is there any other way to accomplish the same thing?
Thanx!
You can create new control derived from DropDown (e.g. DropDownEx), introduce new attributes e.g. DisplayFieldAttribute, ValueFieldAttribute. Then use TypeDescriptor.GetProperties to enumerate properties and analyze attributes for binding them respectively.