如何为多个BO属性定义IDataErrorInfo错误属性

我开始通过IDataErrorInfo接口在我的WPF项目中实现validation。 我的业务对象包含多个带有validation信息的属性。 如何获取与该对象关联的所有错误消息的列表。 我的想法是,这就是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 ; } } 

是的,我知道你可以在哪里使用索引器。 我想,这不是一个糟糕的方式。 我真的专注于’错误’属性。 我喜欢在业务对象中包含错误的概念。 我认为我想做的事情本身并不存在,所以我只是在对象上创建了一个错误字典(在属性发生任何时候更新),并让Error返回一个CarriageReturn分隔的错误列表,如下所示:

  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(FirstName)) msg = "Need a first name"; break; default: throw new ArgumentException( "Unrecognized property: " + property); } if (msg != null && !errorCollection.ContainsKey(property)) errorCollection.Add(property, msg); if (msg == null && errorCollection.ContainsKey(property)) errorCollection.Remove(property); return msg; } } public string Error { get { if(errorCollection.Count == 0) return null; StringBuilder errorList = new StringBuilder(); var errorMessages = errorCollection.Values.GetEnumerator(); while (errorMessages.MoveNext()) errorList.AppendLine(errorMessages.Current); return errorList.ToString(); } } 

我认为使用Validation属性要容易得多。

 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, eg validate paths [File(FileValidation.IsDirectory, ErrorMessage = "Must enter an importfolder")] public string ImportFolder { get; set; } public string this[string columnName] { return InputValidation.Validate(this, columnName); } public ICollection AllErrors() { return InputValidation.Validate(this); } } 

辅助类InputValidation如下所示

 internal static class InputValidation where T : IDataErrorInfo { ///  /// Validate a single column in the source ///  ///  /// Usually called from IErrorDataInfo.this[] /// Instance to validate /// Name of column to validate /// Error messages separated by newline or string.Empty if no errors public static string Validate(T source, string columnName) { KeyValuePair, 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; } ///  /// Validate all columns in the source ///  /// Instance to validate /// List of all error messages. Empty list if no errors public static ICollection Validate(T source) { List messages = new List(); 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; } ///  /// Get all validation attributes on a property ///  ///  ///  private static ValidationAttribute[] GetValidations(PropertyInfo property) { return (ValidationAttribute[])property.GetCustomAttributes(typeof(ValidationAttribute), true); } ///  /// Create a lambda to receive a property value ///  ///  ///  private static Func CreateValueGetter(PropertyInfo property) { var instance = Expression.Parameter(typeof(T), "i"); var cast = Expression.TypeAs(Expression.Property(instance, property), typeof(object)); return (Func)Expression.Lambda(cast, instance).Compile(); } private static readonly Dictionary, ValidationAttribute[]>> mAllValidators; static InputValidation() { mAllValidators = new Dictionary, ValidationAttribute[]>>(); foreach (var property in typeof(T).GetProperties()) { var validations = GetValidations(property); if (validations.Length > 0) mAllValidators.Add(property.Name, new KeyValuePair, ValidationAttribute[]>( CreateValueGetter(property), validations)); } } } 

我的理解是,要使用此接口,您枚举对象的属性,并为每个属性调用一次索引器。 调用者有责任聚合任何错误消息。