The following code works as you’d expect — MyProperty on the model is updated when the user picks a new item in the dropdown.
comboBox1.DataBindings.Add("SelectedValue", myModel, "MyProperty", true,
DataSourceUpdateMode.OnPropertyChanged);
The following, however, doesn’t work the same way and the model update isn’t triggered until the input focus moves to another control on the form:
comboBox1.DataBindings.Add("SelectedItem", myModel, "MyProperty", true,
DataSourceUpdateMode.OnPropertyChanged);
Does anybody know why? I don’t even know where to start investigating the cause. Pointers in the right direction to start the investigation or an outright explanation would be equally appreciated.
Aside: for my purposes, I ended up binding to both SelectedItem and SelectedValue. This way I get instant model updates based on UI changes (through the SelectedValue binding), and UI updates based on programmatic model changes (through the SelectedItem binding).
The ComboBox control inherits from the ListControl control.
The SelectedItem property is a proper member of the ComboBox control. The event that is fired on change is ComboBox.SelectionChangeCommitted
ComboBox.SelectionChangeCommitted
Occurs when the selected item has changed and that change is displayed in the ComboBox.
The SelectedValue property is inherited from the ListControl control.
As such, this property will fire the ListControl.SelectedValueChanged event.
ListControl.SelectedValueChanged
Occurs when the SelectedValue property changes.
That said, they won't fire the INotifyPropertyChanged.PropertyChanged event the same, but they will anyway. The only difference is in the firing event. SelectedValueChanged is fired as soon as a new selection is made from the list part of the ComboBox, and SelectedItemChanged is fired when the item is displayed in the TextBox portion of the ComboBox.
In short, they both represent something in the list part of the ComboBox. So, when binding either property, the result is the same, since the PropertyChanged event is fired in either case. And since they both represent an element from the list, the they are probably treated the same.
Does this help?
EDIT #1
Assuming that the list part of the ComboBox represents a property (as I can't confirm since I didn't write the control), binding either of SelectedItem or SelectedValue affects the same collection inside the control. Then, when this property is changed, the same occurs in the end. The INotifyPropertryPropertyChanged.PropertyChanged event is fired on the same property.
I suspect that the SelectedItem property of the ComboBox does not change until the control has been validated (which occurs when the control loses focus), whereas the SelectedValue property changes whenever the user selects an item.
Here is a reference to the focus events that occur on controls:
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.validated.aspx
This is a long-standing "feature" of the list controls in .NET in my experience. Personally, I would just bind to the on change of the SelectedValue property and write whatever additional code is necessary to workaround this "feature" (such as having two properties, binding to one for SelectedValue, and then, on the set of that property, updating the value from SelectedItem in your custom code).
Anyway, I hope that helps =D
If you want Selected.Value being worked
you have to do following things:
1. Set DisplayMember
2. Set ValueMember
3. Set DataSource (not use Items.Add, Items.AddRange, DataBinding etc.)
The key point is Set DataSource!
If we want to bind to a dictionary ie
<ComboBox SelectedValue="{Binding Pathology, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{x:Static RnxGlobal:CLocalizedEnums.PathologiesValues}" DisplayMemberPath="Value" SelectedValuePath="Key"
Margin="{StaticResource SmallMarginLeftBottom}"/>
then SelectedItem will not work whilist SelectedValue will
Related
I have a WPF ComboBox which I'm using to search names. I use the MVVM pattern and it's all pretty simple:
The ComboBox Text property is bound to a "SearchString" property on the VM. The ComboBox ItemsSource is bound to a "SearchResult" property on the VM. This is a list of objects displayed using a DataTemplate. The ComboBox also triggers a "PreviewKeyDown" event and pressing enter selects the first item in the result set, with up and down arrow keys traversing the results. The SelectedItem is bound to the DataContext for a GroupBox. This part works really nicely.
When an item is selected in the ComboBox, WPF is automatically attempting to replace "Text" with my SelectedItem. This causes my results set to get emptied and "Text" to revert to an empty string.
The behaviour I'd like is that when an item is selected, the text in the ComboBox remains exactly the same, so that my user can continue to traverse the result set using up and down arrows.
Is there an elegant way to achieve this? I think that nothing will be added to the question with a code snippet, but happy to supply if wanted.
The behaviour I'd like is that when an item is selected, the text in the ComboBox remains exactly the same, so that my user can continue to traverse the result set using up and down arrows.
That's a requirement that's not built into the ComboBox control. If you want something like that, you'll have to build it yourself (and subclassing most likely won't help, you'll have to build most of a ComboBox from scratch for this).
In fact you shouldn't be binding the current item like that either, you should use the SelectedItem property, which doesn't do any conversions or copying, exactly what you want for an internal binding.
I must handle SelectedValue property changing to refresh some dependent UI elements when a user selects some item in a ListBox. I use SelectedValue because I need to know a concrete value of the item, not an index in the ListBox (the index may be different under variuos circumstances) or something another. My ListBox is binded to a DataTable and SelectedValue contains ID of a row in the table.
The problem is that when I try to get SelectedValue of the ListBox within SelectionChanged event handler, I receive a prior value, not the current! So, after I spent about a hour searching for ways of solving this problem, I noted that it is relatively well-known, but solutions I've seen do not seem to be very clear. Nevertheless, I "compiled" few ideas I have encountered to the next working snippet of code:
((DataRowView)this.LISTBOXNAME.SelectedItem)["ID"]
where this is my current window and SelectedItem may be casted to DataRowView as the ListBox is binded to a DataTable as I've mentioned before. This line of code gives a proper value of the selected ListBoxItem.
But anyway, I still want to know how to make SelectedValue get proper value directly? Is it possible? Or, maybe, must I use another event (not SelectionChanged)? And if it is impossible, can somebody explain me the way of thinking of kind guys from Microsoft and why that property has such a feature?
SelectedValueChanged event works fine for getting the correct SelectedValue property, so I think the issue may be with how your listbox is setup.
You say you have it bound to a DataTable, so the items in your collection are DataRowView objects.
If you set SelectedValuePath to something like "Id", then the SelectedValue property will attempt to set the SelectedValue to DataRowView.Id, which I don't think is a valid property.
Your two alternatives here are to either
Build a collection of objects with proper properties to use for the SelectedValue
<ListBox ItemsSource="{Binding MyCollection}"
SelectedValue="{Binding SelectedId}"
SelectedValuePath="Id" ... />
where MyCollection is a collection of objects that each contain an .Id property.
Or use SelectedItem instead of SelectedValue, and work with your DataRowView objects as you are now. SelectedItem will be set to the selected item in your collection, which is of type DataRowView, so the code you have posted is how it is accessed.
((DataRowView)this.LISTBOXNAME.SelectedItem)["ID"]
Of the two, the first approach is usually preferred for WPF.
Edit: Here's an answer to your question in the comments below since it was too long to fit in a comment.
A ListBox is meant to be bound to a collection of items. When you set the ItemsSource to a DataTable, you are really binding to a collection of DataRowView objects.
There are 3 ways to get selected item from here: SelectedItem, SelectedIndex, and SelectedValue.
SelectedItem returns you the object that is selected. In this case, that's the DataRowView object, which is why you can cast it to a DataRowView.
SelectedIndex returns you the index of the selected item within the data source.
SelectedValue can only be used if you have also set the SelectedValuePath property. SelectedValuePath tells WPF which property on each data object contains the "Value" of the item, so if you set it to something like "Id", it will try to find the .Id property on each object. In your case, there is no valid property on object DataRowView that would contain your Id column data, so this doesn't work.
Hope that answers your question :)
I have a listbox bound to a List<object> as its DataSource. What I'm wanting to do is use the SelectedValue property of the Listbox (i.e the object corresponding to the current selection) as a DataSource for some textboxes that will display certain values of the object for editing.
I've tried
TextBox.DataBindings.Add(new Binding("Text", ListBox, "SelectedValue.name"));
and
TextBox.DataBindings.Add(new Binding("Text", ListBox.SelectedValue, "name"));
but as there is nothing selected in the ListBox (because the form hasn't been shown yet), I get an exception about "Value cannot be null".
Now I know that I can (re)bind to ListBox.SelectedValue in my form's SelectionChangeCommitted handler (that is, after a selection has been made), but if i have to do that I might as well just set the TextBox's value directly (admittedly I could just do this to resolve the issue, but I'd like to learn more about databinding).
So my question is, in short: Is it possible to bind to ListBox.SelectedValue once (initially, before the ListBox has a selection) and avoid the null value exception, and if so, how?
I'm not sure which control your projectNameCtrl is, but you'll want to bind your TextBox. Something like this:
textBox1.DataBindings.Add(new Binding("Text", listBox1, "selectedvalue"));
Where:
textBox1 is your TextBox
listBox1 is your ListView
EDIT
You should be able to data bind a ListBox even if that ListBox has no selected items so your 'value cannot be null' must be for another reason. I suggest using the debugger to determine which object specifically is null.
You can ensure you don't data bind a control more than once by first checking the control's DataBindings.Count property; if it's equal to zero you haven't yet data bound that control:
if (textBox1.DataBindings.Count == 0) {
// OK to data bind textBox1.
}
Off the top of my head, I think you'd need to do something on each selectedItemChanged event...
I know this doesn't answer your question, but I'd look at using WPF instead since this is so much more elegant to do in WPF, and let's face it, by not creating a GUI in code (using XAML instead) your sanity will be much more intact when you finish your project. I don't recall enough windows forms, but in WPF, you just implement INotifyPropertyChanged on your back-end object that you're binding to, and then when you bind to the SelectedItem property of that ListBox, you automatically get updates since the SelectedItem property is a DependencyProperty.
I have an ItemsControl object and am setting the DataTemplate to hold a Grid with a couple controls in it. The controls are databoud to a collection of some object MyObj, specifically a TextBlock and a ComboBox. MyObj has its own collection inside of it for a property. If that property has only 1 object in its collection, only the TextBlock is visible. But if there is more than 1 object in the collection, the TextBlock is visible and the ComboBox becomes visible once the TextBlock is clicked on.
I have the ComboBox filled up with what it needs, I just can't figure out how to specify which ComboBox needs to become visible when the TextBlock is Clicked on.
I guess my question is, how would I even go about doing this? Or, is there a better way to think about this problem?
I'm new to databinding in Silverlight and running into a bunch of issues on my own. Any help is always appreciated. Thank in advance.
One thing that you could do is add an extra property to the data item that you binding to, something like 'IsSelectionAvailable'. Make the visibility of your combobox bound to this property (via a boolean to Visibility enum Value Converter). Finally, add a click event handler for the text box that sets the IsSelectionAvailable property to true for the object it is bound to.
Hope that helps.
I have a ComboBox whose ItemSource is bound to a list of strings (idealy i would use an Enum), this is done using the MVVM pattern.
Now i want to bind an object to the ComboBox, it's called SelectedUser and i want to bind its property: UserType, which is a string.
So i have got this:
<ComboBox ItemsSource="{Binding Path=Usertypes}" SelectedValue="{Binding Mode=TwoWay, Path=SelectedUser.UserType}" />
It works and it does change the value of the selected user if i play with it, but the problem is, that it does not display anything in the ComboBox unless i select a user, and then change the ComboBox selection, then it works, but only for that user.
I tried playing around with DisplayMemberPath, SelectedValuePath and SelectedItem,
when i added those the ComboBox did not show anything in it (there were still options to select from, but they were invisible or something).
So what should i do? Is this a bug?
I have to mention that i have got another ComboBox that has a list of ints, and it works fine.
Update:
I was informed that I'm getting this issue because the string I'm comparing to the string in the comboBox, are not actually the same.
My string comes from the Entity Framework via Ria Services. (User.UserType)
And when it compares it to the list of strings in the ComboBox ItemSource, they are not equal, for some strange reason.
And i also heard, i might have to override Equal method for that check.
but I'm not sure where and how to do so.
Is the view notified if the SelectedUser changes? I could imagine that this might be the problem; if there is no such notification the ComboBox will not reload the SelectedValue if another user is selected, it will only update the binding if you make changes yourself.
If that is not it, you also need to consider that no selected value will be displayed unless the current value exactly matches one of values in the source list.