【问题标题】:Strange behaviour (or bug?) with ComboBox in WPF when changing DataContext and having bound ItemsSource and SelectedItem更改 DataContext 并绑定 ItemsSource 和 SelectedItem 时,WPF 中 ComboBox 的奇怪行为(或错误?)
【发布时间】:2013-09-22 22:14:52
【问题描述】:

我正在尝试在绑定到 itemssource 和 selecteditem 的组合框中调试一个奇怪的错误。快把我逼疯了。

在修改combobox所在的selected tabitem时会出现问题。(实际上只在修改ComboBox的DataContext时才会出现)。 SelectedItem 绑定有一个自定义验证规则,如果值为 null,则会给出错误。

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

这是我做的一个简化案例,显示相同的错误:

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

更新

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

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>

【问题讨论】:

  • 老兄,你最好像我刚才那样在一个新应用程序中检查你的代码示例,因为它工作得很好没有任何验证错误
  • 如果您在 NotNullValidationRule.Validate 中设置断点,您会看到 WPF 尝试将 null 作为值进行验证。为什么?我的实际应用程序的问题是,这是用于在我们的演示模型中添加失败规则的机制。这个“错误”导致我的模型认为存在错误,因为 null 确实可能是用户设置的值。

标签: c# wpf xaml combobox datacontext


【解决方案1】:

您遇到的问题是由于 wpf 中的 TabControlvirtualized。只有可见选项卡实际存在并与所选项目一起呈现。因此,在切换 tabitem 时,控件会使前一个选项卡无效并使用新选择的项目呈现选项卡,从而触发依赖属性更改,进而触发您的 ValidationRule

所以基本上你必须turn off the Tab virtualization 来解决这个问题。有一些解决方法可以解决这个问题。但是下面的文章提供了一个很好的解决方案:

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

【讨论】:

  • 但是当仅将数据上下文更改为此内容视图时,组合框绑定完全验证似乎并不正常。我的意思是这适用于所有其他控件?如果我只能知道这个空验证不是由用户交互引起的,我也许可以忽略它。无论如何感谢您的意见。
  • 经过更多实验后,我发现 TabControl 实际上是无关紧要的。即使有一个简单的 ComboBox 和一个按钮来切换它的 DataContext 我也遇到了这个问题......
【解决方案2】:

Okai,所以我有很多关于组合框的错误,并且发现顺序很重要。试试这个:

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

设置 x:Name=UserControl。使用 SelectedItem、SelectedValue 和 ItemSource 的顺序、Mode!=Items 中的 OneTime 以及绑定本身会引入一些错误。希望这可以帮助那里的人。

【讨论】:

    【解决方案3】:

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

    我更改绑定顺序的那一刻,它就起作用了! (在 xaml 中)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-10
      • 1970-01-01
      • 2011-02-27
      • 2012-06-23
      • 2015-04-07
      • 2011-11-01
      • 2012-11-05
      • 1970-01-01
      相关资源
      最近更新 更多