Настройка отображения данных с привязкой данных и WPF - Проверка ввода через IDataErrorInfo

ОГЛАВЛЕНИЕ

Проверка ввода через IDataErrorInfo

С появлением Microsoft .NET Framework 3.5 поддержка проверки ввода в WPF радикально улучшилась. Подход ValidationRule полезен для простых приложений, но реальные приложения имеют дело со всей сложностью реальных данных и бизнес-правил. Кодирование бизнес-правил в объекты ValidationRule не только привязывает этот код к платформе WPF, но также и не позволяет бизнес-логике быть там, где ей и положено быть: в бизнес-объектах!

У многих приложений имеется бизнес-слой, где все сложности обработки бизнес-правил заключены в набор бизнес-объектов. При компиляции в Microsoft .NET Framework 3.5 можно воспользоваться интерфейсом IDataErrorInfo, чтобы заставить WPF запрашивать бизнес-объекты о том, находятся ли они в допустимом состоянии или нет. Это избавляет от необходимости размещать бизнес-логику в объектах, отдельных от бизнес-слоя, и позволяет создавать бизнес-объекты, независимые от платформы интерфейса пользователя. Поскольку интерфейс IDataErrorInfo используется уже несколько лет, это также упрощает повторное использование бизнес-объектов из старых приложений Windows Forms или ASP.NET.

Предположим, что необходимо предоставить проверку для эпохи, выходящую за рамки простого обеспечения преобразуемости вводимого пользователем текста в тип данных свойства источника данных. Может иметь смысл не помещать дату начала эпохи в будущее, поскольку мы не знаем об эпохах, которые еще только предстоят. Также может иметь смысл требование, чтобы эпоха длилась не менее одной миллисекунды.

Эти типы правил подобны общей идее бизнес-логики в том, что оба они являются экземплярами правил области. Правила области лучше всего создавать в объектах, которые сохраняют их состояние: объектах области. В коде, приведенном наРис. 14, показан класс SmartEra, предоставляющий сообщения о выявленных проверкой ошибках через интерфейс IDataErrorInfo.

Рис. 14. IDataErrorInfo предоставляет сообщения о выявленных проверкой ошибках

public class SmartEra 
   : System.ComponentModel.IDataErrorInfo
{
   public DateTime StartDate { get; set; }
   public TimeSpan Duration { get; set; }

   #region IDataErrorInfo Members

   public string Error
   {
     get { return null; }
   }

   public string this[string property]
   {
     get 
     {
       string msg = null;
       switch (property)
       {
         case "StartDate":
           if (DateTime.Now < this.StartDate)
             msg = "Start date must be in the past.";
           break;

         case "Duration":
           if (this.Duration.Ticks == 0)
             msg = "An era must have a duration.";
           break;

         default:
           throw new ArgumentException(
             "Unrecognized property: " + property);
       }
       return msg;
     }
   }

   #endregion // IDataErrorInfo Members
}

Употребить поддержку проверки класса SmartEra из интерфейса пользователя WPF очень просто. Нужно лишь указать привязкам, что тем следует принять интерфейс IDataErrorInfo на объекте, к которому они привязаны. Это можно сделать одним из двух способов, как показано наРис. 15.

Рис. 15. Употребление логики проверки

<!-- START DATE -->
<TextBlock Grid.Row="0">Start Date:</TextBlock>
<TextBox Grid.Row="1">
  <TextBox.Text>
   <Binding Path="StartDate" UpdateSourceTrigger="PropertyChanged">
    <Binding.ValidationRules>
     <ExceptionValidationRule />
     <DataErrorValidationRule />
    </Binding.ValidationRules>
   </Binding>
  </TextBox.Text>
</TextBox>

<!-- DURATION -->
<TextBlock Grid.Row="2">Duration:</TextBlock>
<TextBox 
  Grid.Row="3" 
  Text="{Binding 
     Path=Duration, 
     UpdateSourceTrigger=PropertyChanged, 
     ValidatesOnDataErrors=True,
     ValidatesOnExceptions=True}" 
  />

Подобно тому, как правило ExceptionValidationRule можно добавить к коллекции ValidationRules привязки явно или неявно, правило DataErrorValidationRule можно добавить прямо к ValidationRules привязки, или же можно установить свойство ValidatesOnDataErrors на true. Оба подхода дают один и тот же конечный эффект – система привязки запрашивает интерфейс IDataErrorInfo источника данных на предмет выявленных проверкой ошибок.