Why doesn't WPF ComboBox reflect the proper binding value?

I have a ComboBox whose properties ItemsSource and SelectedValue are model bound. Sometimes a model needs to set the selected item to another, but when I do this in the model, the model value is not reflected in the view, even if the selected value is correctly set (marked with both snoop and SelectionChanged event handler).

To illustrate the problem, here is a simple xaml:

<Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525" DataContext="{Binding RelativeSource={RelativeSource Self}}"> <Grid> <ComboBox Height="25" Width="120" SelectedValue="{Binding SelectedValue}" SelectedValuePath="Key" ItemsSource="{Binding PossibleValues}" DisplayMemberPath="Value"/> </Grid> </Window> 

And here is the model:

 using System.Collections.Generic; using System.Windows; using System.ComponentModel; namespace WpfApplication1 { public partial class MainWindow : Window, INotifyPropertyChanged { int m_selectedValue = 2; Dictionary<int, string> m_possibleValues = new Dictionary<int, string>() { { 1, "one" }, { 2, "two" }, { 3, "three" }, {4,"four"} }; public int SelectedValue { get { return m_selectedValue; } set { if (value == 3) { m_selectedValue = 1; } else { m_selectedValue = value; } PropertyChanged(this, new PropertyChangedEventArgs("SelectedValue")); } } public Dictionary<int, string> PossibleValues { get { return m_possibleValues; } set { m_possibleValues = value; } } public MainWindow() { InitializeComponent(); } public event PropertyChangedEventHandler PropertyChanged; } } 

I expected the behavior to be as follows:

  • Two are selected first
  • Choose "one" -> ComboBox will display "one"
  • Choose two -> ComboBox will display two
  • Choose β€œthree” β†’ β€œCombobox” displays β€œ one ”
  • Choose "four" β†’ ComboBox will display "four"

However, in No. 4, β€œthree” is displayed. What for? The value in the model has been changed to 1 ("one"), but 3 ("three") is still displayed in the view.

I found a workaround by explicitly updating the binding target in the SelectionChanged event handler, but this seems to be wrong. Is there any other way to achieve this?

+6
source share
2 answers

When you select an item, the binding engine will update the model and ignore any PropertyChanged for the property that it just changed during the time it calls the property installer. If this were not so, then everything could go into an endless cycle.

The system assumes that the installer does not change the value that it passed. The workaround here is simple: use Dispatcher.BeginInvoke() or set IsAsync=True to your binding to get the behavior you are looking for. However, I personally strongly do not recommend you do this. Not only because it introduces a whole bunch of new timing issues, but mainly because it is a workaround to a problem that should not exist in the first place.

Just don't do it. This is not only applicable to WPF: everything that the installer changes can expect that the value that it just set was correctly set, no exception is thrown. Changing the value inside the setter is intuitive and may bite you later. In addition, for the user of your application it can be very unpleasant to see that the combo box ignores his choice.

If you don't like the value passed, throw an exception and use Binding.ValidatesOnExceptions to tell WPF what it expected. If you do not want the user to select this value, do not put it in the list in the first place. If the item should not be conditionally accessible due to other business rules, filter the list dynamically or apply triggers.

+5
source

I had constant problems updating the control correctly when binding to the SelectedValue and / or SelectedItem properties of the ComboBox control.

To solve this problem, I had to bind to the SelectedIndex property. It was more of a hassle to touch the "index" property in my ViewModel, but it solved the problem with updating the ComboBox .

+2
source

Source: https://habr.com/ru/post/912787/


All Articles