How do I cancel a user selection in a databound WPF ListBox? The source property is set correctly, but the ListBox selection is out of sync.
I have an MVVM app that needs to cancel a user selection in a WPF ListBox if certain validation conditions fail. Validation is triggered by a selection in the ListBox, rather than by a Submit button.
The ListBox.SelectedItem
property is bound to a ViewModel.CurrentDocument
property. If validation fails, the setter for the view model property exits without changing the property. So, the property to which ListBox.SelectedItem
is bound doesn't get changed.
If that happens, the view model property setter does raise the PropertyChanged event before it exits, which I had assumed would be enough to reset the ListBox back to the old selection. But that's not working--the ListBox still shows the new user selection. I need to override that selection and get it back in sync with the source property.
Just in case that's not clear, here is an example: The ListBox has two items, Document1 and Document2; Document1 is selected. The user selects Document2, but Document1 fails to validate. The ViewModel.CurrentDocument
property is still set to Document1, but the ListBox shows that Document2 is selected. I need to get the ListBox selection back to Document1.
Here is my ListBox Binding:
<ListBox
ItemsSource="{Binding Path=SearchResults, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding Path=CurrentDocument, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
I did try using a callback from the ViewModel (as an event) to the View (which subscribes to the event), to force the SelectedItem property back to the old selection. I pass the old Document with the event, and it is the correct one (the old selection), but the ListBox selection doesn't change back.
So, how do I get the ListBox selection back in sync with the view model property to which its SelectedItem
property is bound? Thanks for your help.
I had a very similar problem, the difference being that I am using
ListView
bound to anICollectionView
and was usingIsSynchronizedWithCurrentItem
rather than binding theSelectedItem
property of theListView
. This worked well for me until I wanted to cancel theCurrentItemChanged
event of the underlyingICollectionView
, which left theListView.SelectedItem
out of sync with theICollectionView.CurrentItem
.The underlying problem here is keeping the view in sync with the view model. Obviously cancelling a selection change request in the view model is trivial. So we really just need a more responsive view as far as I'm concerned. I'd rather avoid putting kludges into my ViewModel to work around limitations of the
ListView
synchronization. On the other hand I'm more than happy to add some view-specific logic to my view code-behind.So my solution was to wire my own synchronization for the ListView selection in the code-behind. Perfectly MVVM as far as I'm concerned and more robust than the default for
ListView
withIsSynchronizedWithCurrentItem
.Here is my code behind ... this allows changing the current item from the ViewModel as well. If the user clicks the list view and changes the selection, it will immediately change, then change back if something down-stream cancels the change (this is my desired behavior). Note I have
IsSynchronizedWithCurrentItem
set to false on theListView
. Also note that I am usingasync
/await
here which plays nicely, but requires a little double-checking that when theawait
returns, we are still in the same data context.Then in my ViewModel class I have
ICollectionView
namedItems
and this method (a simplified version is presented).The implementation of
TryCloseAsync
could use some kind of dialog service to elicit a close confirmation from the user.