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)); } }
感谢您的阅读!代码点击这里下载。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。