我正在尝试调试绑定到itemssource和selecteditem的组合框中的奇怪错误 . 这让我疯狂 .
当更改存在组合框的所选tabitem时会出现问题 . (实际上只有在更改ComboBox的DataContext时才会这样) . SelectedItem绑定有一个自定义validationrule,如果value为null,则给出错误 .
问题是wpf在切换tabitems(DataContext)时调用我的自定义规则并尝试验证null值,即使selecteditem-source永远不为null . 这是个问题 .
这是我做的一个简化案例,它显示了同样的错误:
在NotNullValidationRule.Validate中设置断点,并查看WPF如何尝试将SelectedItem验证为null,即使它在任何视图模型实例中都不存在 .
UPDATE
经过一些实验,我发现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>
3 回答
你得到的问题是因为wpf中的
TabControl
是virtualized
. 实际上只存在可见选项卡,并使用所选项目进行渲染 . 因此,在切换tabitem时,控件使前一个选项卡无效,并使用新选择的项目呈现选项卡,从而触发依赖项属性更改,然后启动ValidationRule
.所以基本上你必须
turn off the Tab virtualization
才能解决这个问题 . 有一些解决方法可以解决这个问题 . 但是下面的文章提供了一个很好的解决方案:http://www.codeproject.com/Articles/460989/WPF-TabControl-Turning-Off-Tab-Virtualization
Okai,所以我在comboBox上遇到了很多错误,并发现订单很重要 . 试试这个:
设置x:Name = UserControl . 一些错误将使用SelectedItem,SelectedValue和ItemSource的顺序,Mode!= Items中的OneTime以及ofc绑定本身引入 . 希望这有助于那里的人 .
显然,当设置新的DataContext时,如何更新绑定的顺序是一个问题 . 当ItemsSource绑定获取新的DataContext时,它注意到(在某些情况下)所选项目不在新列表中,然后将SelectedItem设置为null并验证这一点 . 然后,SelectedItem绑定获取与ItemsSource相同的DataContext,更新为正确的值,但没有任何验证以清除以前失败的规则 .
我改变它工作的绑定顺序的那一刻! (在xaml中)