I have a WPF ComboBox and am using MVVM to bind the ItemsSource and SelectedItem properties. Basically what I want to do is when a user selects a specific item in the combobox, the combobox instead selects a different item.
<ComboBox ItemsSource="{Binding TestComboItemsSource}" SelectedItem="{Binding TestComboItemsSourceSelected}"></ComboBox>
For demo purposes, I also have a button to update the SelectedItem.
<Button Command="{Binding DoStuffCommand}">Do stuff</Button>
I have this in my viewModel:
public ObservableCollection<string> TestComboItemsSource { get; private set; }
public MyConstructor()
{
TestComboItemsSource = new ObservableCollection<string>(new []{ "items", "all", "umbrella", "watch", "coat" });
}
private string _testComboItemsSourceSelected;
public string TestComboItemsSourceSelected
{
get { return _testComboItemsSourceSelected; }
set
{
if (value == "all")
{
TestComboItemsSourceSelected = "items";
return;
}
_testComboItemsSourceSelected = value;
PropertyChanged(this, new PropertyChangedEventArgs(TestComboItemsSourceSelected))
}
}
private ICommand _doStuffCommand;
public ICommand DoStuffCommand
{
get
{
return _doStuffCommand ?? (_doStuffCommand = new RelayCommand(p =>
{
TestComboItemsSourceSelected = "items";
})); }
}
OK, so I want to have the ComboBox select the item "items" whenever the user selects the item "all". Using the button, I am able to update the combobox's SelectedItem, and I can see this reflected in the UI
I have similar logic to update the viewModel in my setter of the TestComboItemsSourceSelected property. If the user selects "all", instead set the SelectedItem to "items" So code-wise, the viewmodel property gets changed, but this is not reflected in the UI for some reason. Am I missing something? Is there some sort of side-effect of the way I've implemented this?
Well, this is because you change the property while another change is in progress. WPF will not listen to the PropertyChanged
event for this property while setting it.
To workaround this, you can "schedule" the new change with the dispatcher, so it will be executed after it is done with the current change:
public string TestComboItemsSourceSelected
{
get { return _testComboItemsSourceSelected; }
set
{
if (value == "all")
{
Application.Current.Dispatcher.BeginInvoke(new Action(() => {
TestComboItemsSourceSelected = "items";
}));
return;
}
_testComboItemsSourceSelected = value;
PropertyChanged(this, new PropertyChangedEventArgs(TestComboItemsSourceSelected))
}
}