Оптимизация производительности: привязка данных

Привязка данных Windows Presentation Foundation (WPF) обеспечивает простой и последовательный способ представления данных и взаимодействия с ними для приложений. Элементы можно связывать с данными из различных источников данных в виде объектов CLR и XML.

В этом разделе даются рекомендации по повышению производительности привязки данных.

Как разрешаются ссылки для привязки данных

Прежде чем обсуждать вопросы производительности привязки данных, стоит изучить, как механизм привязки данных Windows Presentation Foundation (WPF) разрешает ссылки на объекты для привязки.

В роли источника привязки данных Windows Presentation Foundation (WPF) может выступать любой объект CLR. Можно выполнять привязку к свойствам, вложенным свойствам или индексаторам объекта CLR. Ссылки привязки разрешаются с помощью отражения Microsoft .NET Framework или ICustomTypeDescriptor. Ниже приведены три метода для разрешения ссылок на объекты для привязки.

Первый метод включает использование отражения. В этом случае объект PropertyInfo используется для обнаружения атрибутов свойства и обеспечивает доступ к метаданным свойства. При использовании интерфейса ICustomTypeDescriptor механизм привязки данных использует этот интерфейс для доступа к значениям свойств. Интерфейс ICustomTypeDescriptor особенно полезен в случаях, когда объект не имеет статический набор свойств.

Уведомления об изменении свойств могут предоставляться путем реализации интерфейса INotifyPropertyChanged или с помощью уведомлений об изменениях, связанных с TypeDescriptor. Однако рекомендуемой стратегией для реализации уведомления об изменении свойств является использование INotifyPropertyChanged.

Если исходный объект — это объект CLR, а исходное свойство — свойство CLR, то механизм привязки данных Windows Presentation Foundation (WPF) должен сначала использовать отражение для исходного объекта, чтобы получить TypeDescriptor, а затем запросить PropertyDescriptor. Эта последовательность операций отражения может занимать очень много времени с точки зрения производительности.

Второй метод разрешения ссылок на объекты включает использование исходного объекта CLR, реализующего интерфейс INotifyPropertyChanged, и исходного свойства, которым является свойство CLR. В этом случае механизм привязки данных использует отражение непосредственно в исходном типе и возвращает необходимое свойство. Это по-прежнему не самый оптимальный метод, но он предъявляет меньше требований к рабочему набору, чем первый метод.

Третий метод разрешения ссылок на объекты включает исходный объект, которым является DependencyObject, и исходное свойство, которым является DependencyProperty. В этом случае механизму привязки данных не нужно использовать отражение. Вместо этого механизм свойства и механизм привязки данных оба разрешают ссылку на свойство независимо. Это оптимальный метод для разрешения ссылок на объекты, используемые для привязки данных.

В следующей таблице сравнивается скорость привязки данных свойства Text одной тысячи элементов TextBlock с помощью этих трех методов.

Привязка свойства Text объекта TextBlock Время привязки (мс) Время отрисовки — включает привязку (мс)
К свойству объекта CLR 115 314
К свойству объекта CLR, который реализует INotifyPropertyChanged 115 305
К свойству DependencyProperty объекта DependencyObject. 90 263

Привязка к большим объектам среды CLR

Привязка данных к одному объекту CLR с тысячами свойств значительно влияет на производительность. Это влияние можно минимизировать путем разделения одного объекта на несколько объектов CLR с меньшим количеством свойств. В таблице показаны время привязки и время отрисовки для привязки данных к одному большому объекту CLR и к нескольким небольшим объектам.

Привязка данных 1000 объектов TextBlock Время привязки (мс) Время отрисовки — включает привязку (мс)
К объекту CLR с 1000 свойств 950 1200
К 1000 объектов CLR с одним свойством 115 314

Привязка к ItemsSource

Рассмотрим сценарий, в котором имеется объект List<T> CLR, содержащий список сотрудников, который требуется отобразить в ListBox Чтобы установить соответствие между этими двумя объектами, нужно привязать список сотрудников к свойству ItemsSource объекта ListBox. Предположим, что к группе присоединяется новый сотрудник. Можно подумать, что для вставки этого человека в список привязанных значений ListBox нужно просто добавить его в список сотрудников, и предположить, что это изменение должно автоматически распознаваться механизмом привязки данных. Это предположение оказалось бы неверным; в действительности изменение не будет автоматически отражено в ListBox. Это объясняется тем, что объект List<T> CLR не вызывает событие изменения коллекции автоматически. Чтобы ListBox применил изменения, необходимо повторно создать список сотрудников и снова присоединить его к свойству ItemsSource объекта ListBox. Хотя это решение работает, оно серьезно влияет на производительность. Каждый раз при повторном назначении свойства ItemsSource объекта ListBox новому объекту ListBox сначала отбрасывает предыдущие элементы и повторно создает весь список. Влияние на производительность увеличивается, если ваш ListBox сопоставляется со сложным DataTemplate.

Эффективным решением этой проблемы является преобразование списка сотрудников в коллекцию ObservableCollection<T>. Объект ObservableCollection<T> создает уведомление об изменении, которое может получить механизм привязки данных. Событие добавляет или удаляет элемент в ItemsControl без необходимости повторного создания восстановления всего списка.

В таблице ниже показано время, необходимое для обновления ListBox (с отключенной виртуализацией пользовательского интерфейса) при добавлении одного элемента. Число в первой строке представляет время, затраченное на привязку объекта List<T> CLR к свойству ListBox элемента ItemsSource. Число во второй строке представляет время, затраченное на привязку объекта ObservableCollection<T> к свойству ListBox элемента ItemsSource. Обратите внимание на значительную экономию времени при использовании стратегии привязки данных ObservableCollection<T>.

Привязка данных ItemsSource Время обновления для 1 элемента (мс)
К объекту List<T> CLR 1656
К ObservableCollection<T> 20

Привязка IList к ItemsControl не IEnumerable

Если у вас есть выбор между привязкой IList<T> или IEnumerable к объекту ItemsControl, следует выбрать объект IList<T>. Привязка IEnumerable к ItemsControl заставляет WPF создать оболочку объекта IList<T>, то есть на производительность будет влиять лишняя нагрузка от второго объекта.

Не преобразовывайте объекты среды CLR в XML только для привязки данных.

WPF позволяет привязать данные к содержимому XML; однако привязка данных к содержимому XML выполняется медленнее, чем привязка данных к объектам CLR. Не преобразуйте данные объекта CLR в XML, если единственной целью этого является привязка данных.

См. также