如何解决使用INotifyDataErrorInfo进行跨属性验证不起作用
我正在尝试在MVVM项目中实施验证,并在Model上完成了验证。下面是一个最小的示例:
查看:
Window x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Test"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<local:VM x:Key="VM"/>
</Window.Resources>
<Grid DataContext="{StaticResource VM}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="Number: "/>
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Number,UpdateSourceTrigger=PropertyChanged,ValidatesOnNotifyDataErrors=True}"
ToolTip="{Binding Path=(Validation.Errors)/ErrorContent,RelativeSource={RelativeSource Mode=Self}}"/>
<Label Grid.Row="1" Grid.Column="0" Content="Limit: "/>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Limit,RelativeSource={RelativeSource Mode=Self}}"/>
</Grid>
</Window>
ViewModel:
public class ViewModel : INotifyPropertyChanged,INotifyDataErrorInfo
{
private Model _model = new Model();
public int Number
{
get { return this._model.Number; }
set
{
if (value != this._model.Number)
this._model.Number = value;
}
}
public int Limit
{
get { return this._model.Limit; }
set
{
if (value != this._model.Limit)
this._model.Limit = value;
}
}
public ViewModel()
{
this._model.PropertyChanged += (sender,args) => this.PropertyChanged?.Invoke(sender,args);
this._model.ErrorsChanged += (sender,args) => this.ErrorsChanged?.Invoke(sender,args);
}
public bool HasErrors => this._model.HasErrors;
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public event PropertyChangedEventHandler PropertyChanged;
public IEnumerable GetErrors(string propertyName) => this._model.GetErrors(propertyName);
}
型号:
public class Model : INotifyPropertyChanged,INotifyDataErrorInfo
{
private int _number;
public int Number
{
get => _number;
set
{
if (_number != value)
{
_number = value;
OnPropertyChanged();
//ValidateNumber();
}
}
}
private int _limit;
public int Limit
{
get => _limit;
set
{
if (_limit != value)
{
_limit = value;
OnPropertyChanged();
ValidateNumber();
}
}
}
private void ValidateNumber()
{
var propertyName = nameof(Number);
if (Number > Limit)
_errors[propertyName] = new[] { "Number cannot be larger than Limit." };
else
{
if (_errors.ContainsKey(propertyName))
_errors.Remove(propertyName);
}
OnErrorChanged(propertyName);
}
private Dictionary<string,IEnumerable<string>> _errors = new Dictionary<string,IEnumerable<string>>();
public bool HasErrors => _errors.Values.Any(err => err != null);
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public IEnumerable GetErrors(string propertyName) => _errors.ContainsKey(propertyName) ? _errors[propertyName] : Enumerable.Empty<object>();
private void OnPropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(propertyName));
private void OnErrorChanged([CallerMemberName] string propertyName = null) => ErrorsChanged?.Invoke(this,new DataErrorsChangedEventArgs(propertyName));
}
在该示例中,只要更改Number
,就应该验证Limit
属性,并且应该在视图上显示Number
的验证错误。但是,观察到验证方法已执行,但视图上的Number
字段未显示验证错误。
从this article看来,INotifyDataErrorInfo
应该支持这种跨属性验证。
解决方法
似乎绑定引擎希望sender
事件的INotifyDataErrorInfo.ErrorsChanged
与绑定源所在的对象相同。
更改
this._model.ErrorsChanged += (sender,args) => this.ErrorsChanged?.Invoke(sender,args);
收件人
this._model.ErrorsChanged += (sender,args) => this.ErrorsChanged?.Invoke(this,args);
解决了该问题。
任何知道为什么这样设计的专家吗? (我花了一整天的时间来解决此问题)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。