2010-09-17 3 views
2

Я реализую проверку данных в WPF с использованием инфраструктуры Prism MVVM. Я использую чистые данные Entities в ViewModel, которые привязаны к слою представления.Проверка достоверности Prism IDataErrorInfo с DataAnnotation на объектах ViewModel

<TextBox Text="{Binding User.Email, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" /> 

Я реализовал общую реализацию IDataErrorInfo в классе ViewModel база, которая проходит проверку против DataAnnotation атрибутов моего лица (в данном случае пользователь).

Проблема в том, что при привязке к объекту инфраструктура WPF ищет IDataErrorInfo для Entity, а не ViewModel, где я хочу, чтобы эта логика существовала. Если я привяжу объект Entity к свойствам в моей модели ViewModel, тогда все будет работать, но я не хочу компрометировать использование Entities в ViewModel.

Есть ли способ сказать WPF искать IDataErrorInfo в ViewModel, а не дочерний объект, который связан?

Спасибо, Майк

ответ

8

Опции Я пошел с было явно реализовать IDataErrorInfo в базовый классе, который продлевается всем ViewModels и лицами. Это кажется лучшим компромиссом для того, чтобы заставить вещи зацикливаться на 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<ValidationResult>(); 
       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<string, object> PropertyLookupCache = 
     new Dictionary<string, object>(); 

    private static Dictionary<string, Func<object, object>> 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<string, Func<object, object>>)PropertyLookupCache[key]; 
    } 

    private static Func<object, object> CreatePropertyGetter(PropertyInfo propertyInfo) 
    { 
     var instanceParameter = Expression.Parameter(typeof(object), "instance"); 

     var expression = Expression.Lambda<Func<object, object>>(
      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); 
    } 


} 
+0

Используете ли вы классы poco для своих объектов? – dnndeveloper

+0

Я хотел, чтобы это было причиной вопроса, в этом решении мои сущности должны расширять DataErrorInfo, однако в противном случае они были бы POCO. – TheCodeKing

2

Конечно, я не знаю весь сценарий, но я считаю, что оборачивать ваши бизнес-объекты (или модель) с использованием ViewModel является большой частью шаблона MVVM, особенно если у вас нет привязываемой модели (модели, к которой вы можете привязать напрямую). Обертка может включать в себя информацию об управлении ошибками, как в этом сценарии, или другие вещи, такие как настройка отображения модели и т. Д.

Таким образом, вы можете взглянуть на Prism v4.0 MVVM RI, который использует проверку INotifyDataErrorInfo для проверки и должны обеспечить интересное понимание подходов к валидации.

Надеюсь, это поможет.

Спасибо, Damian

+0

Спасибо за ваши комментарии Дамиан. Я исследовал INotifyDataErrorInfo некоторое время назад, но, к сожалению, он не поддерживается в WPF. Я уже использую стандартный MVVM, единственная точка привязки - добавление логики проверки для моей сущности, которую я ненавижу делать. Однако, как представляется, это лучший компромисс, чтобы заставить вещи работать элегантно. – TheCodeKing

Смежные вопросы