Strange behavior (or error?) With ComboBox in WPF when changing DataContext and binding ItemsSource and SelectedItem

I am trying to debug a strange error in combobox related to itemssource and selecteditem. It drives me crazy.

The problem occurs when changing the selected tabitem in which the combined function exists. (In fact, this is only when changing the DataContext for the ComboBox). Binding SelectedItem has a custom validationrule function to throw an error if the value is null.

The problem is that wpf calls my custom rule when switching tabitems (DataContext) and tries to check for null, even if the selected source is never zero. This is problem.

This is a simplified case that I made that shows the same error:

Set a breakpoint in NotNullValidationRule.Validate and see how WPF tries to validate the SelectedItem value as null, even if it is not present in any instance of the view model.

UPDATE

After several experiments, I found that TabControl does not actually matter. Even with a simple ComboBox and a button to switch the DataContext, I get the exact same problem. I am replacing the sample code with the new version.

using System.Collections.ObjectModel; using System.ComponentModel; using System.Windows; using System.Windows.Controls; namespace ComboBoxValidationBugTest { public partial class MainWindow : Window { private Test t1, t2; public MainWindow() { InitializeComponent(); t1 = new Test(); t1.Items.Add("A"); t1.Items.Add("B"); t1.Items.Add("C"); t1.SelectedItem = "A"; t2 = new Test(); t2.Items.Add("B"); t2.Items.Add("C"); t2.Items.Add("D"); t2.SelectedItem = "B"; ComboBox1.DataContext = t1; } private void ButtonBase_OnClick(object sender, RoutedEventArgs e) { ComboBox1.DataContext = ComboBox1.DataContext == t1 ? t2 : t1; } } public class Test : INotifyPropertyChanged { private string _selectedItem; private ObservableCollection<string> _items = new ObservableCollection<string>(); public ObservableCollection<string> Items { get { return _items; } } public string SelectedItem { get { return _selectedItem; } set { _selectedItem = value; OnPropertyChanged("SelectedItem"); } } public override string ToString() { return _selectedItem; } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } } public class NotNullValidationRule : ValidationRule { public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo) { if (value == null) { return new ValidationResult(false, "Value was null"); } return new ValidationResult(true, null); } } } 

And XAML:

 <Window x:Class="ComboBoxValidationBugTest.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:comboBoxValidationBugTest="clr-namespace:ComboBoxValidationBugTest" Title="MainWindow" Height="350" Width="525"> <Grid> <DockPanel> <Button Content="Toggle DataContext" DockPanel.Dock="Top" Click="ButtonBase_OnClick" /> <ComboBox ItemsSource="{Binding Items}" VerticalAlignment="Top" x:Name="ComboBox1"> <ComboBox.SelectedItem> <Binding Path="SelectedItem"> <Binding.ValidationRules> <comboBoxValidationBugTest:NotNullValidationRule /> </Binding.ValidationRules> </Binding> </ComboBox.SelectedItem> </ComboBox> </DockPanel> </Grid> </Window> 
+4
source share
3 answers

Apparently, this is a problem with the order of updating the bindings when installing a new DataContext. When ItemSource-binding receives a new DataContext, it notices (in some cases) that the selected item is not in the new list, which then sets the SelectedItem to null and also checks this. Then, the SelectedItem binding gets the same DataContext as the ItemSource, is updated to its correct value, but without any check to eliminate previously broken rules.

The moment I change the order of the bindings, it will work! (in xaml, which is)

0
source

The problem you are getting is that TabControl in wpf is virtualized . Only the visible tab actually exists and is displayed with the selected item. Thus, when switching the tabitem, the control cancels the previous tab and displays the tab with the recently selected item and, therefore, changes the dependency property and, in turn, your ValidationRule .

Basically, you need to turn off the Tab virtualization fix this. There are some ways to solve this problem. But a good solution is presented in the following article:

http://www.codeproject.com/Articles/460989/WPF-TabControl-Turning-Off-Tab-Virtualization

+3
source

Ok, so I had a lot of errors with comboBox and found that order matters. Try the following:

  <ComboBox SelectedValue="{Binding Aldersgrense, NotifyOnValidationError=true, ValidatesOnExceptions=true, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding ElementName=UserControl, Path=DataContext.AldersgrenseTyper, Mode=OneTime}" DisplayMemberPath="Beskrivelse" SelectedValuePath="Verdi" Style="{StaticResource ErrorStyle}"></ComboBox> 

Set x: Name = UserControl. Some errors will be introduced using SelectedItem, the order of SelectedValue and ItemSource, Mode! = OneTime in the Items and ofc of the binding itself. Hope this helps someone out there.

+1
source

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


All Articles