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

时间:2019-10-16 10:32:18

标签: c# wpf validation dependencies

我的视图模型具有2个属性:AB,并且我想验证该A < B

下面是我使用自定义验证规则的简化实现。由于每个属性都是独立验证的,因此会产生麻烦的问题:如果输入的A值无效,那么即使更改了B,它的值也会保持不变,因为B的验证不知道关于A的任何信息。

在此演示中可以看到:

A输入11后无效,从11 > 2开始是正确的。将B更改为22不会重新评估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));
}

查看:

<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);
    }
}

1 个答案:

答案 0 :(得分:6)

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

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

this TechNet article中提供了一个示例。