父子验证规则

问题描述 投票:1回答:1

我在使用ValidationRules时遇到了复杂的情况,我需要一些帮助。我有一个大致这样组织的用户控件:

Parent (ItemsControl)
    Child 1
        Property 1
        Property 2
    Child 2
        Property 1
        Property 2

[Child 1.Property 1更改后,我需要对其进行验证。但是,验证规则要求其子级(所有变量)的子代1,属性1的值以及属性1的值来执行验证。我可以将ValidationRule放在Parent ItemsControl上,但是我需要绑定到Child1.Property1的控件来显示错误。当前,当我将验证放在父级上时,错误显示在父级上,而不是子级上。我也考虑过使用BindingGroups,但我希望更改属性后自动触发验证。据我所知,没有一种方法可以自动为绑定组强制验证。

是否有办法完成我想做的事情?

wpf validationrule
1个回答
0
投票

这是我的解决方法:

namespace WpfValidationRules
{
  using System.ComponentModel.DataAnnotations;
  using System.Globalization;
  using System.Linq;
  using System.Windows.Controls;
  using System.Windows.Data;

  using Microsoft.Xaml.Behaviors;

  using DaValidationResult = System.ComponentModel.DataAnnotations.ValidationResult;
  using WinValidationResult = System.Windows.Controls.ValidationResult;

  public class DataAnnotationsBehavior : Behavior<TextBox>
  {
    protected override void OnAttached()
    {
      var dataItem = Binding.DataItem;
      if (Binding.DataItem == null)
        return;

      var type = dataItem.GetType();
      var prop = type.GetProperty(Binding.ResolvedSourcePropertyName);
      if (prop == null)
        return;

      var allAttributes = prop.GetCustomAttributes(typeof(ValidationAttribute), true);
      foreach (var validationAttr in allAttributes.OfType<ValidationAttribute>())
      {
        var context = new ValidationContext(dataItem, null, null) { MemberName = Binding.ResolvedSourcePropertyName };
        Binding.ParentBinding.ValidationRules.Add(new AttributesValidationRule(context, validationAttr));
      }
    }

    protected override void OnDetaching()
    {
      var das = Binding
        .ParentBinding
        .ValidationRules
        .OfType<AttributesValidationRule>()
        .ToList();

      if (das != null)
        foreach (var da in das)
          Binding.ParentBinding.ValidationRules.Remove(da);
    }

    protected BindingExpression Binding => AssociatedObject.GetBindingExpression(TextBox.TextProperty);

    abstract class DaValidationRule : ValidationRule
    {
      public ValidationContext ValidationContext { get; }

      public DaValidationRule(ValidationContext validationContext)
      {
        ValidationContext = validationContext;
      }
    }

    class AttributesValidationRule : DaValidationRule
    {
      public ValidationAttribute ValidationAttribute { get; }

      public AttributesValidationRule(ValidationContext validationContext, ValidationAttribute attribute)
        : base(validationContext)
      {
        ValidationAttribute = attribute;
      }

      public override WinValidationResult Validate(object value, CultureInfo cultureInfo)
      {
        var result = ValidationAttribute.GetValidationResult(value, ValidationContext);

        return result == DaValidationResult.Success
          ? WinValidationResult.ValidResult
          : new WinValidationResult(false, result.ErrorMessage);
      }
    }
  }
}

用法:

<TextBox Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
    <b:Interaction.Behaviors>
        <local:DataAnnotationsBehavior />
    </b:Interaction.Behaviors>
</TextBox>
© www.soinside.com 2019 - 2024. All rights reserved.