在更改 DataContext 并绑定 ItemsSource 和 SelectedItem 时,WPF 中的 Comb
本文关键字:SelectedItem WPF Comb 中的 ItemsSource DataContext 绑定 | 更新日期: 2023-09-27 18:31:40
我正在尝试调试绑定到项目源和选定项的组合框中的奇怪错误。这让我发疯。
更改组合框所在的选定选项卡项时出现问题。 (实际上,只有在更改组合框的数据上下文时才会出现问题)。SelectedItem 绑定具有自定义验证规则,如果值为 null,则给出错误。
问题是 wpf 在切换选项卡项 (DataContext) 时调用我的自定义规则,并尝试验证 null 的值,即使所选项源永远不会为 null。这是一个问题。
这是我制作的一个简化案例,显示了相同的错误:
在 NotNullValidationRule.Validate 中设置断点,并查看 WPF 如何尝试将 SelectedItem 验证为 null,即使它不存在于任何视图模型实例中。
更新
经过更多的实验,我发现 TabControl 实际上是无关紧要的。即使有一个简单的组合框和一个按钮来切换它的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>
您遇到的问题是由于 wpf 中的TabControl
virtualized
。实际上只有可见选项卡存在,并与所选项目一起呈现。因此,在切换 tabitem 时,控件会使上一个选项卡无效,并使用新选择的项目呈现选项卡,从而触发依赖项属性更改,进而触发您的ValidationRule
。
所以基本上你必须turn off the Tab virtualization
来解决这个问题。有一些解决方法可以解决此问题。但是下面的文章中提供了一个很好的解决方案:
http://www.codeproject.com/Articles/460989/WPF-TabControl-Turning-Off-Tab-Virtualization
Okai,所以我在 comboBox 上遇到了很多错误,并发现顺序很重要。试试这个:
<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:名称=用户控件。一些错误将使用 SelectedItem、SelectedValue 和 ItemSource 的顺序、Mode!=OneTime in Items 以及 ofc 绑定本身引入。希望这对那里的人有所帮助。
这是设置新 DataContext 时绑定更新顺序的问题。当 ItemsSource 绑定获取新的 DataContext 时,它会注意到(在某些情况下)所选项不存在于新列表中,然后将 SelectedItem 设置为 null 并验证这一点。然后,SelectedItem绑定获取与ItemsSource相同的DataContext,更新为其正确的值,但没有任何验证来清除以前失败的规则。
当我改变绑定顺序的那一刻,它就起作用了!(在 XAML 中)