Настройка отображения данных с привязкой данных и WPF - Работа со вводимыми пользователем данными
ОГЛАВЛЕНИЕ
Работа со вводимыми пользователем данными
Для большинства программ отображение данных является лишь половиной дела. Другой серьезной задачей является анализ, принятие и отклонение данных, вводимых пользователем. В идеальном мире, где все пользователи всегда вводят логичные и точные данные, это было бы простой задачей. Но в реальном мире это не так. Реальные пользователи допускают опечатки, забывают вводить необходимые значения, вводят значения не там, где надо, стирают записи, которые не следует стирать, добавляют записи, которые не следуют добавлять и, в целом, следуют законам Мэрфи везде, где это только возможно.
Нашей задачей как разработчиков и архитекторов является борьба с тем, что пользователи неизбежно введут по ошибке или по злому умыслу. Инфраструктура привязки WPF поддерживает проверку ввода. В нескольких следующих разделах этой статьи я объясню, как пользоваться поддержкой проверки в WPF, а также как отображать пользователю сообщения о выявленных проверкой ошибках.
Проверка ввода через ValidationRules
В первой версии платформы WPF, являвшейся частью Microsoft® .NET Framework 3.0, имелась лишь ограниченная поддержка проверки ввода. У класса Binding имелось свойство ValidationRules, в котором могло храниться любое число классов, производных от ValidationRule. Каждое из этих правил могло содержать некоторую логику, проверяющую, является ли привязанное значение допустимым.
В то время в WPF имелся лишь один подкласс правила ValidationRule, именуемый ExceptionValidationRule. Разработчики могли добавить это правило к свойству ValidationRules привязки, после чего оно улавливало исключения, выдаваемые в ходе обновлений источника данных, позволяя интерфейсу пользователя отображать сообщение об ошибке исключения. Полезность этого подхода к проверке ввода спорна, учитывая, что фундаментом хорошего обслуживания пользователей является предотвращение показа им ненужных технических деталей. Сообщения об ошибках в исключениях анализа данных обычно являются такими деталями для большинства пользователей, но вернемся к нашей теме.
Предположим, что у нас имеется класс, представляющий эпоху времени, такой, как простой класс Era, показанный здесь:
public class Era
{
public DateTime StartDate { get; set; }
public TimeSpan Duration { get; set; }
}
Если необходимо позволить пользователю изменять дату начала и продолжительность эпохи, можно использовать два элемента управления «текстовое поле» и привязать их свойства Text к свойствам экземпляра Era. Поскольку пользователь может вводить в текстовое поле всё, что пожелает, нельзя быть уверенным, что введенный текст окажется преобразуемым в экземпляр DateTime или TimeSpan. В данном случае можно использовать ExceptionValidationRule для сообщения об ошибках в преобразовании данных и затем отобразить эти ошибки в интерфейсе пользователя. В коде XAML, приведенном наРис. 11, показано, как можно выполнить эту задачу.
Рис. 11. Простой класс, представляющий эпоху времени
<!-- START DATE -->
<TextBlock Grid.Row="0">Start Date:</TextBlock>
<TextBox Grid.Row="1">
<TextBox.Text>
<Binding Path="StartDate" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<ExceptionValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox><!-- DURATION -->
<TextBlock Grid.Row="2">Duration:</TextBlock>
<TextBox
Grid.Row="3"
Text="{Binding
Path=Duration,
UpdateSourceTrigger=PropertyChanged,
ValidatesOnExceptions=True}"
/>
Эти два текстовых поля демонстрируют два способа, которыми ExceptionValidationRule можно добавить к свойству ValidationRules привязки в XAML. В текстовом поле Start Date («Дата начала») использован развернутый синтаксис элемента свойства, чтобы прямо добавить правило. В текстовом поле Duration («Продолжительность») использован сокращенный синтаксис, который просто устанавливает свойство привязки ValidatesOnExceptions на true. У обеих привязок свойство UpdateSourceTrigger установлено на PropertyChanged, чтобы ввод проверялся каждый раз, когда свойству текстового поля Text дается новое значение, вместо ожидания момента, когда элемент управления потеряет фокус. Снимок экрана программы показан наРис. 12.
Рис. 12. ExceptionValidationRule отображает ошибки проверки
Отображение ошибок проверки
Как показано наРис. 13, текстовое поле Duration содержит неверное значение. Содержащаяся в нем строка не преобразуема в экземпляр TimeSpan. Во всплывающем сообщении текстового поля отображается сообщение об ошибке, и маленький красный значок ошибки появляется на правой стороне элемента управления. Это поведение не является автоматическим, но его легко реализовать и подогнать под конкретный случай.
Рис. 13. Визуализация ошибок, выявленных при проверке ввода, для пользователя
<!--
The template which renders a TextBox
when it contains invalid data.
-->
<ControlTemplate x:Key="TextBoxErrorTemplate">
<DockPanel>
<Ellipse
DockPanel.Dock="Right"
Margin="2,0"
ToolTip="Contains invalid data"
Width="10" Height="10"
>
<Ellipse.Fill>
<LinearGradientBrush>
<GradientStop Color="#11FF1111" Offset="0" />
<GradientStop Color="#FFFF0000" Offset="1" />
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<!--
This placeholder occupies where the TextBox will appear.
-->
<AdornedElementPlaceholder />
</DockPanel>
</ControlTemplate><!--
The Style applied to both TextBox controls in the UI.
-->
<Style TargetType="TextBox">
<Setter Property="Margin" Value="4,4,10,4" />
<Setter
Property="Validation.ErrorTemplate"
Value="{StaticResource TextBoxErrorTemplate}"
/>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<Binding
Path="(Validation.Errors)[0].ErrorContent"
RelativeSource="{x:Static RelativeSource.Self}"
/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
Статический класс Validation формирует взаимоотношения между элементом управления и любыми содержащимися в нем ошибками проверки путем использования прикрепленных свойств и статических методов. На эти прикрепленные свойства можно сослаться в XAML, чтобы создать состоящие из одной разметки описания того, как интерфейс пользователя должен представлять пользователю ошибки, выявленные при проверке ввода. Код XAML наРис. 13 отвечает за объяснение того, как визуализировать сообщения об ошибках ввода для двух элементов управления текстовых полей из предыдущего примера.
Style («Стиль») на Рис. 13 нацелен на все экземпляры текстового поля в интерфейсе пользователя Он применяет к текстовому полю три параметра. Первый, Setter («Метод установки») влияет на свойство Margin («Поля») текстового поля. Свойство Margin устанавливается на значение, которое предоставляет достаточно пространства для отображения значка ошибки с правой стороны.
Следующее свойство Setter в Style присваивает ControlTemplate, используемый для визуализации текстового поля, когда то содержит неверные данные. Оно устанавливает присоединенное свойство Validation.ErrorTemplate на шаблон ControlTemplate, объявленный над Style. Когда класс Validation («Проверка») сообщает, что проверка выявила в текстовом поле одну или несколько ошибок, текстовое поле визуализирует сообщение с помощью этого шаблона. Именно это создает красный значок ошибки, показанный на Рис. 12.
Style также содержит Trigger («Триггер»), отслеживающий прикрепленное к текстовому полю свойство Validation.HasError. Когда класс Validation устанавливает прикрепленное свойство HasError на true для определенного текстового поля, Trigger в Style активируется и присваивает текстовому полю всплывающее сообщение. Содержимое всплывающего сообщения привязано к сообщению об ошибке исключения, выданного при попытке преобразовать текст из текстового поля в экземпляр типа данных свойства источника данных.