更改DataContext并绑定ItemsSource和SelectedItem时,WPF中的ComboBox出现奇怪的行为(或bug?) [英] Strange behaviour (or bug?) with ComboBox in WPF when changing DataContext and having bound ItemsSource and SelectedItem

查看:68
本文介绍了更改DataContext并绑定ItemsSource和SelectedItem时,WPF中的ComboBox出现奇怪的行为(或bug?)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试调试绑定到itemssource和selecteditem的组合框中的奇怪错误.这让我发疯.

I'm trying to debug a strange error in a combobox bound to an itemssource and selecteditem. It's driving me crazy.

在更改存在组合框的选定Tabitem时会出现问题.(实际上仅在更改ComboBox的DataContext时).SelectedItem绑定有一个自定义的验证规则,如果value为null,则会给出错误.

The problem arise when changing selected tabitem in which the combobox exists. (Actually it's only when changing the DataContext of the ComboBox). The SelectedItem-binding has a custom validationrule to give error if value is null.

问题是wpf会在切换 tabitems (DataContext)时调用我的自定义规则,并尝试验证null值,即使selecteditem-source从不为null.这是个问题.

The problem is that wpf calls my custom rule when switching tabitems (DataContext) and tries to validate a value of null, even though the selecteditem-source never is null. This is a problem.

这是我制作的简化案例,它显示了相同的错误:

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

NotNullValidationRule.Validate 中设置一个断点,并查看WPF如何尝试将SelectedItem验证为null,即使它在任何视图模型实例中都不存在.

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

更新

经过更多实验后,我发现TabControl实际上是不相关的.即使使用一个简单的ComboBox和一个用于切换它的DataContext的按钮,我也会遇到完全相同的问题.我正在用新版本替换代码示例.

After some more experimenting I've discovered that the TabControl actually is irrelevant. Even with a simple ComboBox and a button to toggle it's DataContext I get the exact same problem. I'm replacing the code example with a 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);
    }
  }
}

还有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>

推荐答案

显然,设置新的DataContext时如何更新绑定的顺序存在问题.当ItemsSource绑定获取新的DataContext时,它会注意到(在某些情况下)新列表中不存在所选项目,然后将SelectedItem设置为null并对此进行验证.然后,SelectedItem-binding获得与ItemsSource相同的DataContext,并更新为它的正确值,但是没有任何验证以清除以前失败的规则.

Apparently it's a problem with the order of how bindings are updated when a new DataContext is set. When the ItemsSource-binding gets a new DataContext it notices (in some cases) that the selected item is not present in the new list, which then goes about setting SelectedItem to null and also validates this. Then the SelectedItem-binding gets the same DataContext as ItemsSource, is updated to it's correct value but without any validation to clear out previously failed rules.

当我更改绑定顺序的那一刻!(在xaml中)

The moment I changed the order of the bindings it worked! (in xaml that is)

这篇关于更改DataContext并绑定ItemsSource和SelectedItem时,WPF中的ComboBox出现奇怪的行为(或bug?)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆