c#中使用数据验证器

前言

在很多情况下,用户的输入不一定满足我们的设计要求,需要验证输入是否正确,传统的方案是拿到控件数据进行逻辑判定验证后,给用户弹窗提示。这种方法有点职责延后的感觉,数据视图层应该很好的处理用户的输入。使用数据验证器,就可以友好的提示错误信息,让后端不用过多的验证数据正确性。

一、使用效果

二、实现代码

1、校验逻辑

 public class DataErrorInfoModel:NotifyBase
 {
     private string _userName;

     [Required(ErrorMessage ="用户名不能为空")]
     [StringLength(100,MinimumLength =2,ErrorMessage ="最小长度为2")]
     public string UserName
     {
         get { return _userName; }
         set
         {
             _userName = value;
             this.Notify();
         }
     }

     private string _email;

     [Required(ErrorMessage = "邮箱不能为空")]
     [StringLength(100, MinimumLength = 2, ErrorMessage = "最小长度为2")]
     [RegularExpression("^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$",ErrorMessage = "请填写正确的邮箱地址!")]
     public string Email
     {
         get { return _email; }
         set
         {
             _email = value;
             this.Notify();
         }
     }
 }
 public class NotifyBase : INotifyPropertyChanged, IDataErrorInfo
 {
     public string this[string columnName]
     {
         get
         {
             var errors = new List<ValidationResult>();
             Validator.TryValidateProperty(this.GetType().GetProperty(columnName).GetValue(this, null),
                 new ValidationContext(this)
                 {MemberName=columnName
                 }, errors);
             if (errors.Count>0)
             {
                 return string.Join(Environment.NewLine, errors.Select(e => e.ErrorMessage).ToArray());
             }
             return "";
         }
     }

     public string Error => null ;

     public event PropertyChangedEventHandler PropertyChanged;

     public void Notify([CallerMemberName] string propName = "")
     {
         PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
     }
 }

2、WPF前台

 <StackPanel Orientation="Horizontal" Grid.Row="2">
     <TextBox Width="200" Height="40" VerticalContentAlignment="Center" Margin="10"
              Template="{StaticResource ExceptionTextBoxTemplate}"
              Validation.ErrorTemplate="{StaticResource ExceptionTextBoxTemplate}">
         <TextBox.Text>
             <Binding Path="DModel.UserName" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True">
             </Binding>
         </TextBox.Text>
     </TextBox>

     <TextBox Width="200" Height="40" VerticalContentAlignment="Center" Margin="10"
              Template="{StaticResource ExceptionTextBoxTemplate}"
              Validation.ErrorTemplate="{StaticResource ExceptionTextBoxTemplate}">
         <TextBox.Text>
             <Binding Path="DModel.Email" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True">
             </Binding>
         </TextBox.Text>
     </TextBox>
 </StackPanel>

 <ControlTemplate x:Key="ExceptionTextBoxTemplate">
     <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"
             Background="{TemplateBinding Background}" SnapsToDevicePixels="True" CornerRadius="5">
         <Grid>
             <ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" />
             <Border Width="16" Height="16" CornerRadius="8" Margin="5" Background="Red" VerticalAlignment="Center" HorizontalAlignment="Right" Visibility="Collapsed" Name="validation" ToolTip="{Binding (Validation.Errors)[0].ErrorContent,RelativeSource={RelativeSource AncestorType=TextBox, Mode=FindAncestor}}">
                 <TextBlock Text="!" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" />
             </Border>
         </Grid>
     </Border>
     <ControlTemplate.Triggers>
         <Trigger Property="IsEnabled" Value="false">
             <Setter Property="Opacity" TargetName="border" Value="0.56" />
         </Trigger>
         <Trigger Property="IsMouseOver" Value="true">
             <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.MouseOver.Border}" />
         </Trigger>
         <Trigger Property="IsKeyboardFocused" Value="true">
             <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.Focus.Border}" />
         </Trigger>
         <Trigger Property="Validation.HasError" Value="true">
             <Setter Property="BorderBrush" Value="Red" TargetName="border" />
             <Setter Property="Visibility" Value="Visible" TargetName="validation" />
             <Setter Property="ToolTip" Value="{Binding (Validation.Errors)[0].ErrorContent,RelativeSource={RelativeSource Self}}" />
             <!--<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />-->
         </Trigger>
     </ControlTemplate.Triggers>
 </ControlTemplate>

3、控件关联(绑定数据源)

 this.DataContext = new DataErrorInfoViewModel();

三、FluentValidation扩展版本

1、校验逻辑

public class TemplateMatchParamValidator : AbstractValidator<TemplateMatchParam>
    {
        public TemplateMatchParamValidator()
        {
            /*
             *   .NotNull()                属性不是 null
             *   .NotEmpty()               属性不是 null、空字符串或空格 (或值类型的默认值, 例如 int 0)。
             *   .NotEqual()               值不等于特定值 (或不等于其他属性的值)
             *   .Equal()                  值等于特定值 (或等于另一个属性的值)
             *   .Length()                 长度位于指定范围内。但是, 它不能确保字符串属性是否为 null。
             *   .MaxLength()              长度不超过指定的值
             *   .MinLength()              长度不能小于指定的值。
             *   .LessThan()               值小于特定值 (或小于另一个属性的值)
             *   .LessThanOrEqualTo()      值小于等于特定值 (或小于等于另一个属性的值)
             *   .GreaterThan()            值大于特定值 (或大于另一个属性的值)
             *   .GreaterThanOrEqualTo()   值大于等于特定值 (或大于等于另一个属性的值)
             *   .Must()                   值传递到一个委托中, 可以对该值执行自定义验证逻辑
             *   .Matches()                正则表达式验证
             *   .Email ()                 电子邮件验证
             *
             *   .InclusiveBetween()      介于两者之间包括边界
             *   .ExclusiveBetween()      介于两者之间不包括边界
             *
             */
            RuleFor(vm => vm.Greed)
                .NotNull()
                .InclusiveBetween(0.01, 1)
                .WithMessage($"请正确输入贪婪度:0.01-1");

            RuleFor(vm => vm.MaxOverlay)
                .NotNull()
                .InclusiveBetween(0.01, 1)
                .WithMessage($"请正确输入最大重叠:0.01-1");

            RuleFor(vm => vm.MatchScore)
                .NotNull()
               .InclusiveBetween(0.1, 1)
               .WithMessage($"请正确输入匹配分数:0.1-1");

            RuleFor(vm => vm.Threshold)
                .NotNull()
               .InclusiveBetween(10, 200)
               .WithMessage($"请正确输入梯度阈值:10-200");

            RuleFor(vm => vm.MinLength)
               .NotNull()
             .InclusiveBetween(1, 100)
             .WithMessage($"请正确输入最小长度:1-100");

            RuleFor(vm => vm.TimeOut)
               .NotNull()
            .InclusiveBetween(1, 10000)
            .WithMessage($"请正确输入超时:1-10000");

            RuleFor(vm => vm.MinAngle)
               .NotNull()
            .InclusiveBetween(-180, 180)
            .WithMessage($"请正确输入最小角度:-180-180");

            RuleFor(vm => vm.MaxAngle)
              .NotNull()
           .InclusiveBetween(-180, 180)
           .WithMessage($"请正确输入最大角度:-180-180");

            RuleFor(vm => vm.MinRate)
               .NotNull()
           .InclusiveBetween(0.6, 1)
           .WithMessage($"请正确输入最小比例:0.6-1");

            RuleFor(vm => vm.MaxRate)
               .NotNull()
           .InclusiveBetween(1, 1.5)
           .WithMessage($"请正确输入最大比例:1-1.5");
        }

    }
    public class TemplateMatchParam : BindableBase, IDataErrorInfo
    {
 //其他代码省略

        // <summary>
        /// 当前属性设置错误信息,用于检验用户设置的参数是否正确
        /// </summary>
        public string Error
        {
            get
            {
                var results = validator.Validate(this);
                if (results != null && results.Errors.Any())
                {
                    var distinctRes = results.Errors.GroupBy(x => x.PropertyName).Select(y => y.FirstOrDefault());
                    var errors = string.Join(Environment.NewLine, distinctRes.Select(x => x.ErrorMessage).ToArray());
                    return errors;
                }
                if (LearnImage == null || !LearnImage.IsInitialized())
                {
                    return "模板没有学习!";
                }

                return string.Empty;
            }
        }

        public string this[string columnName]
        {
            get
            {
                if (validator == null)
                {
                    validator = new TemplateMatchParamValidator();
                }
                var firstOrDefault = validator.Validate(this)
                    .Errors.FirstOrDefault(lol => lol.PropertyName == columnName);
                return firstOrDefault?.ErrorMessage;
            }
        }
        private TemplateMatchParamValidator validator { get; set; }
    }

2、WPF前台

  <TextBox
                    Grid.Row="1"
                    Grid.Column="1"
                    Style="{StaticResource ParamSetHaveErrorTbStyle}"
                    Text="{Binding TemplateMatchParam.Threshold, ValidatesOnDataErrors=True}" />

3、使用效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值