Dynamic Forms Control Properties - c#

I'm creating a capture form on the fly based on a set of metadata held in a EAV type schema.
My trouble is in load the data back to the control, and in particular a winforms combobox.
Also using Entity Framework for the data that is bound to the control.
Check is control exist, else create. for each mapped property set their values.
i.e. Datasource, DisplayMember, ValueMember, etc...
Load value is exists to SelectedValue property? this is where is fails?
On inspection of the object it seems as if none of the previous values including the datasource has been loaded yet? But the combobox does show the values once rendered?
Here are some snippets of the code.
Type oType = Type.GetType("System.Windows.Forms.ComboBox");
if (oControlObject == null)
{
oControlObject = (Control)Activator.CreateInstance(oType);
oControlObject.Tag = item;
oControlObject.CreateControl();
}
...Loop to set Datasource, DisplayMember & ValueMember ...
if (property.IsReadProperty.Value && value != null)
{
PropertyInfo propSet = oType.GetProperty(property.PropertyName); //PropertyName here is "SelectedValue"
propSet.SetValue(oControlObject, value.Value, null);
}

Got it working. The problem is that the control is not initialized until it is rendered on the form, thus no items collection, even though the datasource is set.
Built up the dynamic form first and then populated the save values by iterating through the controls again... not elegant but it works, until i have another solution.

Related

How get the value of disabled ComboBox?

i have a lot of trouble with my CUIT. I want to test my window with data from database. The window is so constructed that some fields are deactivated so that the user can not change the values. The ComboBox gets a value, but in CUIT I can not read this value, because the control is not enabled. That's why I can not read properties of control right, SelectedIndex is f.e. always -1. Is there any way to find the text of ComboBox?
if you are working with WpfComboBox, you can obtain all items of the combobox by getting the property Items. It returns you basically UITestControlCollection and you can enumerate through its elements:
foreach (UITestControl uiTestControl in yourUiTestControlCollection)
{
string name = uiTestControl.FriendlyName;
}
or similarly by using lambda-expressions.
In this case it does not matter which item is selected and in which state (Enabled = true/false;) the combobox is.
However, it might not help if your combobox loads all the items somehow dynamically when changing its state to enabled. Then you will have to find another test scenario to make the combobox enabled before you analyze it with your test method.
Hope it will help.

How do I pass a grid's Datasource through to the PropertyGrid?

I have a grid wrapped in a user control. I need to pass the datasource of the grid through the control.
// My Pass-Through declaration
public object DataSource
{
get { return internalGrid.DataSource; }
set ( internalGrid.DataSource = value; }
}
So far, that's the easy part. The datasource of the grid is a plain Object. The pass-through Datasource is also a plain Object.
When I drop a datagrid directly on my form, I can set datasource by selecting one of my binding source objects on my form. However, when I include my custom control, the pass-through datasource is grayed out. I can't select the binding sources.
I'm certain that I am simply missing a property attribute, but I don't know which one(s). Any help would be appreciated.

Combobox SelectedItem does not work

I have the code below
FooCB.DisplayMember = "FooNome";
FooCB.ValueMember = "Foo";
FooCB.DataSource = FooRepository.Instance.All();
FooCB.DataBindings.Add("SelectedItem", Bar, "Foo");
but when I display the form the SelectedItem is always the first.
What am I doing wrong?
I have been struggling a little with the behaviour of Winforms comboboxes and databinding recently and these are my observations (.Net4) when binding the ComboBox.DataSource to a list of items and also binding an object property to ComboBox.SelectedItem.
When binding a list of objects (in your case List<Foo>) to ComboBox.DataSource, the first object in the list is always shown in the combobox.
If you bind an object property to ComboBox.SelectedItem (in your case Bar.Foo) and that object property matches one of the combobox list objects then that object is displayed in the combobox. If the object property is null (Bar.Foo == null) or the object property is not in the combobox list then the first object is shown in the combobox.
Setting ComboBox.SelectedItem = null or ComboBox.SelectedIndex = -1 clears the displayed item on the combobox even though this seems to warn against it. And will set your bound object property to null.
If a user clears the combobox selection when using ComboBox.DropDownStyle == DropDown (with backspace) then the bound object property is set to null.
If you have implemented INotifyPropertyChanged on the object whose property is bound to Combobox.SelectedItem (Bar.Foo) and you programatically set the bound property to a value and that value appears in the combobox list then the changed value will be displayed. If you set the property to null or a value not in the list then the combobox displayed value will not change.
So what can you do about it? The only real issue I have is having no value displayed when my bound property is null so I have just been explicitly setting Combobox.SelectedItem = null as in point #3. You may be able to extend ComboBox and override the default behaviour but so far I have been content with an extra line of code here and there combined with using default values on non-nullable properties.
Probably you are missing some decleration. If you created the Combobox from the Tool Box, -I had the similar problem- you might want to add name of the Combobox's Name as a tag on XAML.
Other than that, if you created it dynamically by code, check if you are missing any decleration for class.
I can't tell from the OP's code whether I'm answering their question, but maybe this will help somebody reading this question. The ComboBox has four ways to set the current value:
SelectedIndex
SelectedItem
SelectedText
SelectedValue
You need to be consistent about what you're setting (and about which event handler you're using). You'll get an error if you set SelectedIndex to something dumb (less than -1 or longer than the list). However, you don't get errors setting the other three to something that doesn't exist for that type of selection.
Suppose you use a Dictionary (that's pseudo code) as a binding source and set DisplayMember = "Value" and ValueMember = "Key", the mapping would look like:
SelectedIndex - -1 to index of last item
SelectedItem - KeyValuePair<Key, Value>
SelectedText - Dictionary value
SelectedValue - Dictionary key
Supplying either value or key to SelectedItem will not generate an error, it will simply act like the OP has described. And that's why I thought this answer might help somebody.
I might also note that, if you're swapping out the contents of the ComboBox, it's not always safe to use SelectedIndex. Suppose the same basic kind of data is in the ComboBox, but selections are limited in some cases compared to others. Using SelectedIndex to persist a previous selection that was still valid in the new list of options is only going work if that previous selection held the exact same place in the list. You'd almost think this was the voice of very, very recent experience speaking...

Designer-editing DataSource property of a DataGridView within a UserControl

I have a custom UserControl that contains several child controls, amongst which is a DataGridView. I don't want to EnableDesignMode for any of the child controls, but instead have exposed and serialized their properties as needed. I'm stuck on DataGridView's DataSource property.
Do I need to make a custom UITypeEditor and use reflection to find all the BindingSource objects on the parent form for selection, or can I somehow invoke the built-in editor of this type? What type is the editor invoked when changing DataGridView's DataSource?
EDIT: Actually, the suggestion from Oliver did not quite work out. I did get the list of bindable objects in the property grid when I select my UserControl and after I chose a binding source, columns of bound dataset appeared on the grid, but columns of datagridview are not serialized to designer.cs after editing the Columns collection. However, if I build a custom ParentControlDesigner and EnableDesignMode for this datagridview, I can set the binding via it's DesignerVerb, and then the Columns collection is serialized after editing.
I exposed datagridview's Columns and DataSource properties in this way
[Editor(typeof(CollectionEditor), typeof(UITypeEditor))]
[Category("Grid")]
//[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public DataGridViewColumnCollection Columns
{
get { return dgvListaBaza.Columns; }
}
[AttributeProvider(typeof(IListSource))]
[Browsable(true)]
[Category("Grid")]
public object DataSource
{
get { return dgvList.DataSource; }
set { dgvList.DataSource = value; }
}
What is the difference between the way DataSource is set when I click on the control's native designerverb and the one through exposed property? Both show the columns of the bindingSource in the grid after i choose a binding, but Columns don't get serialized in the latter case, as if there is something else I need to set when setting the DataSource.
Also, DesignerSerializationVisibility attribute on the exposed Columns makes no difference, and the column Names in the CollectionEditor are different depending on the way I set the DataSource (If it's set through native designerverb, then they are named SomeColumnDataGridViewTextBoxColumn, and if it's set through the property, then the Name property of each column is empty).
Take a look at DataSource for User Control.

A ComboBox Data Binding Question

I have an interesting data binding question related to combobox. Hope someone has some good suggestion.
I have a simple form, it contains a file picker and a comboxbox. Every time a file is picked, I read a list of strings from the file to a List object and I set comboBox.DataSource = listOfStrings.
In the form load event, I set comboBox.DataBindings.Add("SelectedItem", myObject, "PickedValue");
The purpose is clear: every time a string is selected from the combobox, I want to write the string to myObject.PickedValue.
That is the whole story.
Now I launch the form, rather than go pick a file, I check the combobox first. Of course, at this point, comboBox.DataSource is null, comboBox.SelectedItem is null, too. But the data binding on the comboBox is already setup (since the setting is in form load event). Now my focus cannot be moved from the combobox to anywhere else.
I think the reason is, when I try to check the combobox, it has null as SelectedItem. When I try to move the focus to somewhere else, the data binding of the combobox is triggered. Underlying, it tries to convert the selected item to string and update myObject.PickedValue with that converted string. Since you cannot convert a null to a string, the data binding validation fails, and the validation mechanism doesn't allow my focus to be moved elsewhere and I am sucked at this moment, cannot even move to pick a file.
My question is, what is the normal binding setup work-flow for my application scenario to prevent this trap? What is the correct order of setting up such a data binding so I can check my combobox before its data source is filled by something?
FYI, I tried to bind myObject.PickedValue to SelectedText property of the combobox (I noticed that SelectedText is a string and never be null, even when SelectedItem is null). But interestingly, even if I select something from the combobox, SelectedText is still empty string when data binding is triggered. What's wrong here?
Thanks for any help.
The failure is a little simpler than you describe: Your ComboBox will fail just because there is no selected item, because there's nothing to select from.
I would just disable the ComboBox if there's nothing to select from. It's pretty easy to do. Remember to hook up a PropertyChanged event in your data object; the binding source will find it automatically with reflection.
class MyData
{
public event PropertyChangedEventHandler PropertyChanged;
// ...
public HasListOfStrings { get { return ListOfStrings != null && 0 < ListOfStrings.Count; } }
private void LoadListOfStrings
{
// ... load the list of strings ...
if ( PropertyChanged) {
PropertyChanged(this, "ListOfStrings");
PropertyChanged(this, "HasListOfStrings");
}
}
}
In the designer, bind the 'Enabled' property of the 'ComboBox' to the HasListOfStrings property. You can do it in code with:
listOfStringsComboBox.Bindings.Add ("Enabled", bindingSource, "HasListOfStrings");
I also recommend you change the AutoValidate property of the container (or container's container) to EnableAllowFocusChange.
This doesn't seem right; it should be possible to set a string property to null. Possibly the focus problem lies elsewhere. Have you tried setting a breakpoint on your property setter to confirm your theory?
The SelectedText property of a combo box refers to text that has been selected in the text portion of the combobox. This only works if the dropdown style is set to combo. Basically it's the selected text of the text box portion of the combo control (the reason a combobox is called "combo" is because it is a combination of a textbox and a selection list). You would ordinarily expect this property to be empty unless the user was editing the text portion of the combo.
If you want a workaround for this problem that is consistent with a good user experience, try disabling the combo box on form load, then enabling it when a file is picked.

Categories