在ViewModel实体上使用DataAnnotation进行Prism IDataErrorInfovalidation

我正在使用Prism MVVM框架在WPF中实现数据validation。 我在ViewModel中使用干净的数据实体,这些实体被绑定到表示层。

 

我在基础ViewModel类中实现了IDataErrorInfo的通用实现,该类对我的Entity上的DataAnnotation属性运行validation(在本例中为User)。

问题是当绑定到实体时,WPF框架在实体上查找IDataErrorInfo而不是ViewModel,这是我希望这个逻辑存在的地方。 如果我用我的ViewModel中的属性包装我的实体,那么一切正常,但我不希望在ViewModel中妥协使用实体。

有没有办法告诉WPF在ViewModel中查找IDataErrorInfo而不是被绑定的子对象?

谢谢,迈克

我选择的选项是在基类中显式实现IDataErrorInfo,该基类由所有ViewModel和Entities扩展。 这似乎是使用WPF解决问题的最佳折衷方案,并且至少将IDataErrorInfo的实现隐藏到调用者,因此它们至少看起来很干净。 我公开了一个受保护的ValidateProperty,如果需要,可以在子类中覆盖任何自定义行为(例如Password / PasswordConfirmation场景)。

 public abstract class DataErrorInfo : IDataErrorInfo { string IDataErrorInfo.Error { get { return null; } } string IDataErrorInfo.this[string columnName] { get { return ValidateProperty(columnName); } } protected virtual string ValidateProperty(string columnName) { // get cached property accessors var propertyGetters = GetPropertyGetterLookups(GetType()); if (propertyGetters.ContainsKey(columnName)) { // read value of given property var value = propertyGetters[columnName](this); // run validation var results = new List(); var vc = new ValidationContext(this, null, null) { MemberName = columnName }; Validator.TryValidateProperty(value, vc, results); // transpose results var errors = Array.ConvertAll(results.ToArray(), o => o.ErrorMessage); return string.Join(Environment.NewLine, errors); } return string.Empty; } private static readonly Dictionary PropertyLookupCache = new Dictionary(); private static Dictionary> GetPropertyGetterLookups(Type objType) { var key = objType.FullName ?? ""; if (!PropertyLookupCache.ContainsKey(key)) { var o = objType.GetProperties() .Where(p => GetValidations(p).Length != 0) .ToDictionary(p => p.Name, CreatePropertyGetter); PropertyLookupCache[key] = o; return o; } return (Dictionary>)PropertyLookupCache[key]; } private static Func CreatePropertyGetter(PropertyInfo propertyInfo) { var instanceParameter = Expression.Parameter(typeof(object), "instance"); var expression = Expression.Lambda>( Expression.ConvertChecked( Expression.MakeMemberAccess( Expression.ConvertChecked(instanceParameter, propertyInfo.DeclaringType), propertyInfo), typeof(object)), instanceParameter); var compiledExpression = expression.Compile(); return compiledExpression; } private static ValidationAttribute[] GetValidations(PropertyInfo property) { return (ValidationAttribute[])property.GetCustomAttributes(typeof(ValidationAttribute), true); } } 

当然,我不知道您的整个场景,但我相信使用ViewModel包装您的业务实体(或模型)是MVVM模式的重要组成部分,特别是如果您没有可绑定模型(模型到你可以直接绑定)。 包装可以包括本场景中的错误管理信息或其他内容,例如自定义模型显示等。

也就是说,您可以查看Prism的v4.0 MVVM RI,它使用INotifyDataErrorInfo进行validation,并且应该提供有关validation方法的有趣见解。

我希望这有帮助。

谢谢,达米安