Привязка данных
Привязка данных (data binding) – это отношение, которое используется для извлечения информации из источника данных и установки свойства зависимостей в целевом объекте . Целевой объект обычно является элементом управления. Источником данных может быть произвольный объект .NET. Привязка способна (при определённых условиях) автоматически обновлять целевое свойство при изменении данных источника.
Очевидно, что при определении привязки нужно указать целевое свойство, источник данных и правило извлечения информации из источника. Кроме этого, можно выполнить настройку следующих параметров:
1. Направление привязки. Привязка может быть однонаправленной (целевое свойство меняется при изменении данных источника), двунаправленной (изменения в источнике и целевом объекте влияют друг на друга) и от цели к источнику (источник данных обновляется при изменении целевого свойства).
2. Условие обновления источника. Если привязка двунаправленная или от цели к источнику, можно настроить момент обновления источника данных.
3. Конвертеры значений. Привязка может выполнять автоматическое преобразование данных при их перемещении от источника к целевому объекту и наоборот.
4. Правила проверки данных. Привязка может включать правила проверки данных на корректность и поведение, выполняемое при нарушении этих правил.
В WPF привязка данных описывается либо декларативно, либо в коде. В любом случае используется объект класса System.Windows.Data.Binding (унаследованный от MarkupExtension).
Класс System.Windows.Data.BindingOperations предоставляет набор статических методов для управления привязкой в коде. В частности, метод GetBinding() позволяет получить привязку для указанного целевого объекта и его свойства зависимостей, метод SetBinding() устанавливает привязку, а метод ClearBinding() удаляет привязку.
Источники и поставщики данных
Источник данных для привязки может быть задан при помощи следующих свойств объекта Binding: ElementName, Source, RelativeSource. Эти свойства являются взаимоисключающими – установив одно из них, остальные следует сбросить, иначе при выполнении привязки генерируется исключение.
Строковое свойство ElementName удобно использовать, чтобы определить в качестве источника данных элемент, который принадлежит одному логическому дереву вместе с целевым объектом.
Свойство Source даёт возможность указать в качестве источника привязки произвольный объект.
Свойство привязки RelativeSource позволяет задать источник данных на основе отношения к целевому объекту.
Если при описании привязки не задано ни одно из свойств ElementName, Source, RelativeSource, источник данных определяется на основе значения свойства DataContext целевого объекта. Если у целевого объекта это свойство не установлено, будет выполнен поиск по дереву элементов для нахождения первого родительского DataContext, не равного null.
Технология WPF поддерживает механизм поставщиков данных (data providers), чтобы упростить декларативную настройку доступа к источникам данных. В настоящее время имеется два поставщика: ObjectDataProvider получает информацию, вызывая заданный метод, а XmlDataProvideг доставляет данные непосредственно из источника XML. Все поставщики данных унаследованы от класса System.Windows.Data.DataSourceProvider.
Обновление данных и направление привязки
Ранее было отмечено, что привязка способна автоматически обновлять целевое свойство при изменении источника данных. Чтобы реализовать этот функционал, можно поступить одним из следующих способов:
1. Сделать свойство источника данных свойством зависимостей.
2. Генерировать при изменении источника событие Имя-Свойства Changed.
3. Реализовать в источнике интерфейс INotifyPropertyChanged (пространство имён System.ComponentModel), содержащий событие PropertyChanged. Это событие нужно генерировать при изменении данных, указывая имя свойства.
Для того чтобы изменения в целевом свойстве попадали в источник данных, нужно установить режим привязки в BindingMode.TwoWay или BindingMode.OneWayToSource.
Конвертеры значений
Конвертер значений отвечает за преобразование данных при переносе из источника в целевое свойство и за обратное преобразование в случае двунаправленной привязки.
Для создания конвертера значений требуется выполнить четыре шага.
1. Создать класс, реализующий интерфейс IValueConverter.
2. Применить к классу атрибут [ValueConversion ] и специфицировать исходный и целевой типы данных (необязательный шаг).
3. Реализовать метод Convert(), выполняющий преобразование данных от источника к целевому объекту.
4. Реализовать метод ConvertBack(), делающий обратное преобразование.
Проверка данных
Для привязки, которая передаёт информацию в источник данных (режимы BindingMode.TwoWay и BindingMode.OneWayToSource) можно выполнить проверку данных перед помещением их в источник. Если данные не проходят проверку, то источник не обновляется.
Первый способ организации проверки заключается в создании и применении проверочных правил . Каждое проверочное правило – это наследник класса System.Windows.Controls.ValidationRule с перекрытым методом Validate() . Этот метод получает проверяемое значение и информацию о культуре, а возвращает объект ValidationResult с результатом проверки.
Второй способ организации проверки основан на генерации исключительной ситуации в методе установки свойства источника данных
Исключительные ситуации, возникающие при передаче информации в источник, отлавливаются при помощи специального встроенного правила ExceptionValidationRule.
Третий способ организации проверки основан на реализации источником данных интерфейса System.ComponentModel.IDataErrorInfo . Интерфейс IDataErrorInfo содержит два элемента: строковое свойство Error и строковый индексатор с ключом-строкой. Свойство Error – это общее описание ошибок объекта. Индексатор принимает имя свойства и возвращает соответствующую детальную информацию об ошибке. Ключевая идея в том, что вся логика обработки ошибок централизована в индексаторе.
Четвёртый вариант организации проверки основан на реализации источником данных интерфейса System.ComponentModel.INotifyDataErrorInfo. Этот интерфейс похож на гибрид интерфейсов INotifyPropertyChanged и IDataErrorInfo . Его булево свойство HasErrors указывает на наличие ошибок объекта. Метод GetErrors() позволяет получить список ошибок по строке с именем свойства. Событие ErrorsChanged необходимо генерировать при изменении списка ошибок.