4

Я потратил последний час или около того для поиска ответа на этот вопрос, но почти каждый результат либо в ASP.NET, либо говорит о подходах Code First, которые мне бесполезны.Как отобразить сообщение об ошибке для DataAnnotations

У меня в основном созданы объекты POCO для объектов базы данных, которые я предоставляю для проверки использования IDataErrorInfo.

Теперь это работает нормально, за исключением того, что у меня есть указатель длиной 200 строк с примерно 40 if-statements в нем. (Я серьезно).

Что я делаю прямо сейчас расширяет классы так:

public partial class MyPocoObject : IDataErrorInfo 
{ 
    public string Error 
    { 
     get { throw new NotImplementedException("IDataErrorInfo.Error"); } 
    } 

    public string this[string columnName] 
    { 
     get 
     { 
      string result = null; 

      // There's about 40 if statements here... 
     } 
    } 
} 

Очевидно, что это неправильно, поэтому я пытаюсь использовать DataAnnotations вместо этого.

Это то, что я понял до сих пор.

Я создал классы метаданных, как так:

[MetadataType(typeof(MyObjectMetaData))] 
public partial class MyObject { } 

public class MyObjectMetaData 
{ 
    [Required(AllowEmptyStrings = false, ErrorMessage = "Forename is a required field.")] 
    public string Forename; 
} 

Тогда я контролирует декларируется в качестве такового:

<TextBox Text="{Binding SelectedObject.Forename, NotifyOnValidationError=True, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"/> 

Тогда у меня есть триггер в другом месте:

<Style TargetType="TextBox" BasedOn="{StaticResource Global}"> 
    <Style.Triggers> 
     <Trigger Property="Validation.HasError" Value="true"> 
      <Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self},Path=(Validation.Errors)[0].ErrorContent}"/> 
     </Trigger> 
    </Style.Triggers> 
</Style> 

Когда я сделал это с помощью IDataErrorInfo, когда проверка не удалась, я получил бы красную рамку и всплывающую подсказку с помощью er сообщение. Используя аннотации данных, я ничего не получаю.

Как я могу реализовать это? Потому что 40 if-операторов в одном методе безумны.

Обновление: Я пробовал код, предложенный в ответах, которые не работают, хотя я думаю, что я сделал это неправильно.

public partial class Member : IDataErrorInfo 
{ 
    // Error: The type 'Project.Client.Models.Member' already contains a definition for 'Forename' 
    [Required(AllowEmptyStrings = false, ErrorMessage = "Forename is a required field.")] 
    public string Forename; 

    private readonly Dictionary<string, object> _values = new Dictionary<string, object>(); 

    public string Error 
    { 
     get { throw new NotImplementedException("IDataErrorInfo.Error"); } 
    } 

    public string this[string columnName] 
    { 
     get { return OnValidate(columnName); } 
    } 


    protected virtual string OnValidate(string propertyName) 
    { 
     if (string.IsNullOrEmpty(propertyName)) 
     { 
      throw new ArgumentException("Invalid property name", propertyName); 
     } 

     string error = string.Empty; 
     // Error: Project.Client.Models.Member.GetValue<T>(string)' cannot be inferred from the usage. Try specifying the type arguments explicitly 
     var value = GetValue(propertyName); 
     var results = new List<System.ComponentModel.DataAnnotations.ValidationResult>(1); 
     var result = Validator.TryValidateProperty(
      value, 
      new ValidationContext(this, null, null) 
      { 
       MemberName = propertyName 
      }, 
      results); 

     if (!result) 
     { 
      var validationResult = results.First(); 
      error = validationResult.ErrorMessage; 
     } 

     return error; 
    } 

    protected T GetValue<T>(string propertyName) 
    { 
     if (string.IsNullOrEmpty(propertyName)) 
     { 
      throw new ArgumentException("Invalid property name", propertyName); 
     } 

     object value; 
     if (!_values.TryGetValue(propertyName, out value)) 
     { 
      value = default(T); 
      _values.Add(propertyName, value); 
     } 

     return (T)value; 
    } 
} 

Update 2: код связан в статье на MVVM, кажется, работает, но никаких сообщений об ошибках не по-прежнему отображается даже OnValidate стреляет.

Хотя сейчас что-то не так ... Несмотря на то, что содержимое текстового поля меняется, значение, возвращаемое из GetValue, всегда одно и то же, и на пустой объект, не загруженный из моей базы данных, проверка не срабатывает все.

ответ

0

я оказался фиксируя это сам путем привязки к свойству в ViewModel, а не самой модели и добавление аннотаций к просмотру а не пытаться расширить и загромождать модель.

Думая об этом, я, вероятно, должен был это сделать первым ....

0

Некоторые технологии .NET извлекают и обрабатывают метаданные, а другие нет. Попробуйте зарегистрировать класс напарником перед использованием:

var myObjectMetadaProviderProvider = new AssociatedMetadataTypeTypeDescriptionProvider(typeof(MyObject), typeof(MyObjectMetaData)); 
TypeDescriptor.AddProvider(myObjectMetadaProviderProvider , typeof(MyObject)); 

Это позволяет получить атрибуты, объявленные в классе напарников прозрачным способом без необходимости знать о MetadataTypes в главном классе.

+0

Где я могу это добавить? Модель просмотра или где-то еще? Я пробовал как viewmodel, так и конструктор класса 'App', и ни один из них не работал. – Jake

+0

При загрузке приложения должно работать. – jlvaquero

+0

Это не так, поэтому я, наверное, что-то пропустил. У вас есть ссылка или что-то, на что я могу ссылаться? – Jake

1

Кажется, вам необходимо интегрировать проверку данных DataAnnotations вручную. Возможно, System.ComponentModel.DataAnnotations.Validator не использует MetadataType по умолчанию, но регистрация его в TypeDescriptor, как в моем предыдущем ответе, должна работать.

Article Code

Что я имею в виду, что вы должны реализовать метод проверки и использовать System.ComponentModel.DataAnnotations.Validator.

Возьмите добычу на реализацию PropertyChangedNotification исходного кода я связан:

/// <summary> 
     /// Validates current instance properties using Data Annotations. 
     /// </summary> 
     /// <param name="propertyName">This instance property to validate.</param> 
     /// <returns>Relevant error string on validation failure or <see cref="System.String.Empty"/> on validation success.</returns> 
     protected virtual string OnValidate(string propertyName) 
     { 
      if (string.IsNullOrEmpty(propertyName)) 
      { 
       throw new ArgumentException("Invalid property name", propertyName); 
      } 

      string error = string.Empty; 
      var value = GetValue(propertyName); 
      var results = new List<System.ComponentModel.DataAnnotations.ValidationResult>(1); 
      var result = Validator.TryValidateProperty(
       value, 
       new ValidationContext(this, null, null) 
       { 
        MemberName = propertyName 
       }, 
       results); 

      if (!result) 
      { 
       var validationResult = results.First(); 
       error = validationResult.ErrorMessage; 
      } 

      return error; 
     } 
+0

Что вы подразумеваете под рукой? Добавляю ли я аннотации в частичном классе, потому что, если я добавлю их в Модели, я потеряю их, как только будет построено решение. – Jake

+0

Я также пробовал эту статью, и она бросает System.ArgumentException, жалуясь на дату рождения, которую я еще не реализовал. Это дает мне дополнительную информацию: значение свойства DateOfBirth должно быть типа «System.DateTime». – Jake

+0

Я пробовал код, который вы связали в своем ответе, но он генерирует исключение в DateOfBirth, которое Я еще не добавил аннотации. Я пытаюсь заставить Forename работать, прежде чем я реализую все остальное. – Jake

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