【发布时间】:2020-02-13 02:41:21
【问题描述】:
我有具有 2 个属性的视图模型:A 和 B,我想验证 A < B。
下面是我使用自定义验证规则的简化实现。由于每个属性都是独立验证的,因此会导致一个令人讨厌的问题:如果输入的 A 值无效,那么即使在更改 B 后它也会保持不变,因为 B 的验证不知道任何关于 A 的信息。
这可以在这个演示中看到:
A在输入11后无效,因为11 > 2是正确的。将B 更改为22 不会重新评估A,我必须编辑A 才能通过验证。
我想要什么?我希望在将22 转换为B 后,红色边框(验证错误)消失,A = 11, B = 22 将是视图模型中的源值。
在新的B 值与源同步后,我如何在B 验证中以某种方式强制A 验证?
查看模型:
public class ViewModel : INotifyPropertyChanged
{
int _a;
public int A
{
get => _a;
set
{
_a = value;
OnPropertyChanged();
}
}
int _b;
public int B
{
get => _b;
set
{
_b = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
public virtual void OnPropertyChanged([CallerMemberName] string property = "") =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
查看:
<StackPanel>
<TextBox Margin="10" Text="{local:MyBinding A}" />
<TextBox Margin="10" Text="{local:MyBinding B}" />
</StackPanel>
查看代码:
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel { A = 1, B = 2 };
}
绑定:
public class MyBinding : Binding
{
public MyBinding(string path) : base(path)
{
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
ValidationRules.Add(new MyValidationRule());
}
}
验证规则:
public class MyValidationRule : ValidationRule
{
public MyValidationRule() : base(ValidationStep.ConvertedProposedValue, false) { }
public override ValidationResult Validate(object value, CultureInfo cultureInfo) => ValidationResult.ValidResult; // not used
public override ValidationResult Validate(object value, CultureInfo cultureInfo, BindingExpressionBase owner)
{
var binding = owner as BindingExpression;
var vm = binding?.DataItem as ViewModel;
switch (binding.ResolvedSourcePropertyName)
{
case nameof(vm.A):
if ((int)value >= vm.B)
return new ValidationResult(false, "A should be smaller than B");
break;
case nameof(vm.B):
if ((int)value <= vm.A)
return new ValidationResult(false, "B should be bigger than A");
break;
}
return base.Validate(value, cultureInfo, owner);
}
}
【问题讨论】:
-
如果在
A的设置器中也调用OnPropertyChanged(nameof(B))是否有效(以及B的设置器的等效项)? -
Validationrule 只适用于简单的用例。 vm 中的 inotifydataerrorinfo 是处理任何实质性内容的常用方法。看看流利的验证。介绍示例:gist.github.com/holymoo/11243164fluentvalidation.net/built-in-validators Offhand - 两个属性可能具有相同的规则,谓词检查都很好。
-
仅当您直接公开模型时才相关。不要直接暴露模型。使用视图模型。只提交有效数据。
-
@Sinatr:“我发现验证规则的概念更正确”是错误的。如果你想执行这种验证,你应该在你的视图模型中实现
INotifyDataErrorInfo。验证规则不支持。 -
@Rekshino,是的,我也在考虑何时验证
A:在验证B之前或之后(换句话说,在B 的值被接受并与源同步之前或之后)。订购事宜。实际上,首先我必须准备好所有修改过的值,然后才能按正常顺序进行验证。
标签: c# wpf validation dependencies