天天看點

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}"/>