如何验证两个相互依赖的属性?

Sin*_*atr 8 c# validation wpf dependencies

我有2个属性视图模型:AB我想验证A < B

以下是我使用自定义验证规则的简化实现。由于每个属性都是独立验证的,因此会带来一个麻烦的问题:如果输入的A值无效,那么即使更改后它也会保持不变B,因为对的验证B一无所知A

在此演示中可以看到:

A输入后是无效的11,因为是11 > 2。更改B22不会重新评估A,我必须进行编辑A才能通过验证。

我想要的是?我希望在22变为B红色边框(验证错误)后消失并A = 11, B = 22成为视图模型中的源值。

新值与源同步后,如何在B验证中以某种方式强制A验证B


查看模型:

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));
}
Run Code Online (Sandbox Code Playgroud)

视图:

<StackPanel>
    <TextBox Margin="10" Text="{local:MyBinding A}" />
    <TextBox Margin="10" Text="{local:MyBinding B}" />
</StackPanel>
Run Code Online (Sandbox Code Playgroud)

查看代码:

public MainWindow()
{
    InitializeComponent();
    DataContext = new ViewModel { A = 1, B = 2 };
}
Run Code Online (Sandbox Code Playgroud)

捆绑:

public class MyBinding : Binding
{
    public MyBinding(string path) : base(path)
    {
        UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        ValidationRules.Add(new MyValidationRule());
    }
}
Run Code Online (Sandbox Code Playgroud)

验证规则:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

mm8*_*mm8 6

ValidationRules 不支持在设置另一个属性时使一个属性无效。

您应该做的是INotifyDataErrorInfo在您的视图模型中实现并在ErrorsChanged每次您想要刷新属性的验证状态时引发事件。

此TechNet文章中提供了一个示例。