天天看点

WPF MVVM ValidationAttribute IDataErrorInfo 验证

首先 TextBox验证不通过的触发样式--> 从网上找的代码段

引用:
    xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"




样式:
<LinearGradientBrush x:Key="TextBoxBorder" EndPoint="0,20" StartPoint="0,0" MappingMode="Absolute">
        <GradientStop Color="#ABADB3" Offset="0.05"/>
        <GradientStop Color="#E2E3EA" Offset="0.07"/>
        <GradientStop Color="#E3E9EF" Offset="1"/>
    </LinearGradientBrush> 

<Style BasedOn="{x:Null}" TargetType="{x:Type TextBox}"> 
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
        <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
        <Setter Property="BorderBrush" Value="{StaticResource TextBoxBorder}"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="Padding" Value="1"/>
        <Setter Property="AllowDrop" Value="true"/>
        <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TextBox}">
                    <Grid x:Name="root">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="1"/>
                        </Grid.ColumnDefinitions>
                         <Microsoft_Windows_Themes:ListBoxChrome x:Name="Bd" SnapsToDevicePixels="true" Background="{TemplateBinding Background}" 
                                                                BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" 
                                                                RenderFocused="{TemplateBinding IsKeyboardFocusWithin}" RenderMouseOver="{TemplateBinding IsMouseOver}">
                                <ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                            </Microsoft_Windows_Themes:ListBoxChrome>

                            <Border x:Name="border"  BorderBrush="#FFDB000C" BorderThickness="1" CornerRadius="1" Visibility="Collapsed"  HorizontalAlignment="Stretch" Margin="0" Width="Auto">

                                <Grid Background="Transparent" HorizontalAlignment="Right" Height="12" Margin="1,-4,-4,0" VerticalAlignment="Top" Width="12">
                                    <Path Data="M 1,0 L6,0 A 2,2 90 0 1 8,2 L8,7 z" Fill="#FFDC000C" Margin="1,3,0,0"/>
                                    <Path Data="M 0,0 L2,0 L 8,6 L8,8" Fill="#ffffff" Margin="1,3,0,0"/>
                                </Grid>
                            </Border>
                        <Popup  AllowsTransparency="True" x:Name="popup" Placement="Bottom" IsOpen="False">
                            <Border x:Name="border1_Copy"   Width="Auto" Height="Auto" Background="Transparent" BorderThickness="0" BorderBrush="Transparent">
                                <TextBlock Margin="0,1,0,0" TextWrapping="NoWrap"  Foreground="Red" Text="{Binding (Validation.Errors)[0].ErrorContent, RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Center" VerticalAlignment="Center" />
                            </Border>
                        </Popup> 
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="Validation.HasError" Value="True">
                            <Setter Property="Visibility" TargetName="border" Value="Visible"/>
                        </Trigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="Validation.HasError" Value="True"/>
                                <Condition Property="IsFocused" Value="True"/>
                            </MultiTrigger.Conditions>
                            <Setter Property="IsOpen" TargetName="popup" Value="True"/>
                        </MultiTrigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
           

一个类的属性验证可能会发生 多个属性值互相关联的情况

比如 a、b、c 、d 四个属性值:d<c<b<a

则用ValidationAttribute 方式验证 直接在属性值上面验证方式需要自定义 验证类

public class Example: INotifyPropertyChanged , IDataErrorInfo  
{ 
    private int _b;  
    [ValidateRelation("A", "C", 100, 1)]         //A、C为待验证关联属性名
    public int B{ 
    get { return _b; }
    set
       {
        if (_b != value)
        {    
           _b = value;
           OnPropertyChanged(new PropertyChangedEventArgs("B"));
        }
       }
}
           

验证类:

//ValidateRelation

using System.ComponentModel.DataAnnotations;   

    /// <summary>
    ///关联验证类
    /// </summary>
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] //指定在那些元素可以使用该特性
    public class ValidateRelation : ValidationAttribute
    {
        public ValidateRelation(string lessComparePropertyPara,string moreComparePropertyPara,int maxValuePara,int minValuePara)
        {
            LessCompareProperty = lessComparePropertyPara;
            MoreCompareProperty = moreComparePropertyPara;
            MaxValue = maxValuePara;
            MinValue = minValuePara;
        }


        /// <summary>
        /// 比较的值 的属性名称(比较对象) 当前值小于 lessCompareProperty则验证通过
        /// </summary>
        public string LessCompareProperty  { get; set; } 

        /// <summary>
        /// 比较的值 的属性名称(比较对象)当前值大于 MoreCompareProperty则验证通过
        /// </summary>
        public string MoreCompareProperty   { get; set; }

        /// <summary>
        /// 比较大小  最大值
        /// </summary>
        public int MaxValue   { get; set; }

        /// <summary>
        /// 比较大小  最小值
        /// </summary>
        public int MinValue  { get; set; }


         

        /// <summary>
        /// 此方法先于 IsValid(object value)调用 
        /// </summary>
        /// <param name="value"></param>
        /// <param name="validationContext"></param>
        /// <returns></returns>
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var curCompareValue = (int)value;//当前待验证的值
            //validationContext.ObjectInstance 待验证对象
            //validationContext.ObjectType   待验证对象类型
            var tempData = Convert.ChangeType(validationContext.ObjectInstance, validationContext.ObjectType);//创建待验证对象
            bool isInt = false;
            int lessCompareValue = -1;
            PropertyInfo lessPropertyInfo = null;
            if (LessCompareProperty != "")
            {
                lessPropertyInfo = validationContext.ObjectType.GetProperty(LessCompareProperty); //获取指定名称的属性 
                isInt = int.TryParse(lessPropertyInfo.GetValue(tempData, null).ToString(), out lessCompareValue);
            }

           
            int moreCompareValue = -1;
            PropertyInfo morePropertyInfo  = null;
            if (MoreCompareProperty!="")
            {
                morePropertyInfo = validationContext.ObjectType.GetProperty(MoreCompareProperty); //获取指定名称的属性 
                isInt = int.TryParse(morePropertyInfo.GetValue(tempData, null).ToString(), out   moreCompareValue);
            }

            

            if (!isInt) //获取属性值   
            {
                //如果类型不正确
                return new ValidationResult($"{LessCompareProperty}不是整型");
            }
            else
            {

                //首先比较大小   比较大小 比较通过 则 继续走else
                if (!ValidateIntCommon.CheckIntValue(value, MaxValue, MinValue))
                {
                    return new ValidationResult($"该项值范围(" + MinValue + "-" + MaxValue + ")");
                }
                else
                {

                    //比较2个值  返回错误消息
                    //可以根据业务自定义添加参数 比较是否需要等于 
                    if (curCompareValue >= lessCompareValue && lessCompareValue > 0)
                    {
                        if (LessCompareProperty.ToLower().Contains("A"))
                        {
                            return new ValidationResult($"该项值小于A");
                        } 
                        else
                        {
                            return new ValidationResult($"该项值输入的值错误");
                        }
                    }
                    else if (curCompareValue <= moreCompareValue && moreCompareValue >= 0)
                    {
                        if (MoreCompareProperty.ToLower().Contains("C"))
                        {
                            return new ValidationResult($"该项值大于C");
                        }
                        else
                        {
                            return new ValidationResult($"该项值输入的值错误");
                        }
                    }
                    else 
                    { 
                         return base.IsValid(value, validationContext); 
                    }
                }
            }
           
        }
         
        public override bool IsValid(object value)
        { 
            return ValidateIntCommon.CheckIntValue(value, MaxValue, MinValue);
        } 
}
           

前端引用:

<TextBox  x:Name="tb_B" Text="{Binding B,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,ValidatesOnDataErrors=True}"/>