1. 程式人生 > >WPF中使用Data Annotations驗證Model

WPF中使用Data Annotations驗證Model

原文: WPF中使用Data Annotations驗證Model

.NET Framework中System.ComponentModel.DataAnnotations提供了很多屬性來驗證物件的屬性。可以在C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\{.NET Version}\路徑下面找到System.ComponentModel.DataAnnotations.dll

public class User
{
    [Required]
    [StringLength(
20)] public string Name { get; set; } [Range(1,120)] public int Age { get; set; } }

檢查一個例項是否合法有效,使用下面的程式碼,具體可以參考: https://msdn.microsoft.com/en-us/library/dd411772%28v=vs.110%29.aspx

Validator.TryValidateObject(obj,new ValidationContext(obj),results,true);
static void Main(string
[] args) { ICollection<ValidationResult> results = null; User invalidUser = new User { Name = "My name is System.ComponentModel.DataAnnotations", Age = -1, }; if(!Validate(invalidUser, out results)) { Console.WriteLine(string.Join("
\n", results.Select(o=>o.ErrorMessage))); } else { Console.WriteLine("I am a valid object."); } Console.ReadKey(); } static bool Validate<T>(T obj, out ICollection<ValidationResult> results) { results = new List<ValidationResult>(); return Validator.TryValidateObject(obj, new ValidationContext(obj), results, true); }

程式碼中例項化了一個非法的User,程式碼執行結果如下:

這些ErrorMessage是.NET提供的,如果需要自定義錯誤資訊可以在Attribute上增加ErrorMessage,程式碼如下:

public class User
{
    [Required]
    [StringLength(20, ErrorMessage ="Out of range~")]
    public string Name { get; set; }

    [Range(1,120, ErrorMessage ="Not a valid age.")]
    public int Age { get; set; }
}

執行結果如下:

如果將User的屬性修改為合法的值,結果如下:

User validUser = new User
{
    Name = "Hellen",
    Age = 18,
};

在WPF中,繼承IDataErrorInfo介面,通過IDataErrorInfo來傳遞Data Annotation的ErrorMessage。

class PropertyValidateModel : IDataErrorInfo
{
    public string this[string columnName]
    {
        get
        {
            List<ValidationResult> validationResults = new List<ValidationResult>();

            bool result = Validator.TryValidateProperty(
                GetType().GetProperty(columnName).GetValue(this),
                new ValidationContext(this)
                {
                    MemberName = columnName
                },
                validationResults);

            if (result)
                return null;

            return validationResults.First().ErrorMessage;
        }
    }

    public string Error
    {
        get
        {
            return null;
        }
    }
}

這裡只驗證單個屬性,下面是Model類,注意:Model需要繼承INotifyPropertyChanged介面,直接看程式碼,

class User : PropertyValidateModel, INotifyPropertyChanged
{
    private string _name = string.Empty;

    private int _age = 0;

    [Required]
    [StringLength(20)]
    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            if(_name != value)
            {
                _name = value;

                RaisePropertyChanged("Name");
            }
        }
    }

    [Required]
    [Range(1,120)]
    public int Age
    {
        get
        {
            return _age;
        }
        set
        {
            if(_age != value)
            {
                _age = value;

                RaisePropertyChanged("Age");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void RaisePropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

下面看一下UI這一塊的ErrorMessage繫結

<StackPanel>
    <TextBlock Text="Name: "/>
    <TextBox Text="{Binding User.Name,UpdateSourceTrigger=PropertyChanged, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" Margin="0,10">
        <Validation.ErrorTemplate>
            <ControlTemplate>
                <StackPanel>
                    <AdornedElementPlaceholder x:Name="textBox" />
                    <TextBlock Text="{Binding [0].ErrorContent}" Foreground="Red"/>
                </StackPanel>
            </ControlTemplate>
        </Validation.ErrorTemplate>
    </TextBox>
    <TextBlock Text="Age" />
    <TextBox Text="{Binding User.Age, UpdateSourceTrigger=LostFocus, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" Margin="0,10">
        <Validation.ErrorTemplate>
            <ControlTemplate>
                <StackPanel>
                    <AdornedElementPlaceholder x:Name="textBox" />
                    <TextBlock Text="{Binding [0].ErrorContent}" Foreground="Red"/>
                </StackPanel>
            </ControlTemplate>
        </Validation.ErrorTemplate>
    </TextBox>
</StackPanel>

執行結果如下:

補充一個內容:

如何自定義一個ValidationAttribute。只需要繼承ValidationAttribute,並重寫IsValid方法即可。例如:

    public class DivisibleBy7Attribute : ValidationAttribute
    {
        public DivisibleBy7Attribute()
            :base("{0} value is not divisible by 7")
        {
        }

        protected override ValidationResult IsValid(
            object value, 
            ValidationContext validationContext)
        {
            decimal val = (decimal)value;

            bool vaild = val % 7 == 0;

            if (vaild)
                return null;
            return new ValidationResult(base.FormatErrorMessage(validationContext.MemberName));
        }
    }

感謝您的閱讀!程式碼點選這裡下載。