How can I define a IDataErrorInfo Error Property for multiple BO properties

后端 未结 3 1643
一个人的身影
一个人的身影 2021-02-06 01:20

I\'m starting to implement validation in my WPF project via the IDataErrorInfo interface. My business object contains multiple properties with validation info. How do I get a l

3条回答
  •  感情败类
    2021-02-06 02:04

    I think it is much easier to use the Validation attributes.

    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.Validate(this, columnName);
        }
    
        public ICollection AllErrors() {
            return InputValidation.Validate(this);
        }
    }
    

    The helper class InputValidation looks like this

    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));
            }       
        }
    }
    

提交回复
热议问题