我开始通过IDataErrorInfo接口在我的
WPF项目中实现验证.
我的业务对象包含多个具有验证信息的属性.如何获取与该对象相关联的所有错误消息的列表.我的想法是,这是什么Error属性,但我无法追踪任何人使用此报告多个属性.
我的业务对象包含多个具有验证信息的属性.如何获取与该对象相关联的所有错误消息的列表.我的想法是,这是什么Error属性,但我无法追踪任何人使用此报告多个属性.
谢谢!
public string this[string property] { get { string msg = null; switch (property) { case "LastName": if (string.IsNullOrEmpty(LastName)) msg = "Need a last name"; break; case "FirstName": if (string.IsNullOrEmpty(LastName)) msg = "Need a first name"; break; default: throw new ArgumentException( "Unrecognized property: " + property); } return msg; } } public string Error { get { return null ; } }
解决方法
我认为使用验证属性要容易得多.
class MyBusinessObject { [required(ErrorMessage="Must enter customer")] public string Customer { get; set; } [Range(10,99,ErrorMessage="Price must be between 10 and 99")] public decimal Price { get; set; } // I have also created some custom attributes,e.g. validate paths [File(FileValidation.IsDirectory,ErrorMessage = "Must enter an importfolder")] public string ImportFolder { get; set; } public string this[string columnName] { return InputValidation<MyBusinessObject>.Validate(this,columnName); } public ICollection<string> AllErrors() { return InputValidation<MyBusinessObject>.Validate(this); } }
辅助类InputValidation看起来像这样
internal static class InputValidation<T> where T : IDataErrorInfo { /// <summary> /// Validate a single column in the source /// </summary> /// <remarks> /// Usually called from IErrorDataInfo.this[]</remarks> /// <param name="source">Instance to validate</param> /// <param name="columnName">Name of column to validate</param> /// <returns>Error messages separated by newline or string.Empty if no errors</returns> public static string Validate(T source,string columnName) { KeyValuePair<Func<T,object>,ValidationAttribute[]> validators; if (mAllValidators.TryGetValue(columnName,out validators)) { var value = validators.Key(source); var errors = validators.Value.Where(v => !v.IsValid(value)).Select(v => v.ErrorMessage ?? "").ToArray(); return string.Join(Environment.NewLine,errors); } return string.Empty; } /// <summary> /// Validate all columns in the source /// </summary> /// <param name="source">Instance to validate</param> /// <returns>List of all error messages. Empty list if no errors</returns> public static ICollection<string> Validate(T source) { List<string> messages = new List<string>(); foreach (var validators in mAllValidators.Values) { var value = validators.Key(source); messages.AddRange(validators.Value.Where(v => !v.IsValid(value)).Select(v => v.ErrorMessage ?? "")); } return messages; } /// <summary> /// Get all validation attributes on a property /// </summary> /// <param name="property"></param> /// <returns></returns> private static ValidationAttribute[] GetValidations(PropertyInfo property) { return (ValidationAttribute[])property.GetCustomAttributes(typeof(ValidationAttribute),true); } /// <summary> /// Create a lambda to receive a property value /// </summary> /// <param name="property"></param> /// <returns></returns> private static Func<T,object> CreateValueGetter(PropertyInfo property) { var instance = Expression.Parameter(typeof(T),"i"); var cast = Expression.TypeAs(Expression.Property(instance,property),typeof(object)); return (Func<T,object>)Expression.Lambda(cast,instance).Compile(); } private static readonly Dictionary<string,KeyValuePair<Func<T,ValidationAttribute[]>> mAllValidators; static InputValidation() { mAllValidators = new Dictionary<string,ValidationAttribute[]>>(); foreach (var property in typeof(T).GetProperties()) { var validations = GetValidations(property); if (validations.Length > 0) mAllValidators.Add(property.Name,new KeyValuePair<Func<T,ValidationAttribute[]>( CreateValueGetter(property),validations)); } } }