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 :)