Оптимизация производительности: привязка данных
Привязка данных 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
Рассмотрим сценарий, в котором у вас есть объект CLRList<T>, содержащий список сотрудников, которые необходимо отобразить в ListBox. Чтобы создать соответствие между этими двумя объектами, необходимо привязать список сотрудников к свойству ItemsSourceListBox. Однако предположим, что у вас новый сотрудник, вступающий в вашу группу. Вы можете подумать, что чтобы вставить этого нового пользователя в привязанные значения ListBox, вы просто добавите этого человека в список сотрудников и ожидаете, что это изменение будет распознано подсистемой привязки данных автоматически. Это предположение окажется ложным; в действительности изменение не будет отражено в ListBox автоматически. Это связано с тем, что объект CLRList<T> не вызывает событие изменения коллекции автоматически. Чтобы заставить ListBox учесть изменения, потребуется заново создать список сотрудников и снова прикрепить его к свойству ItemsSourceListBox. Хотя это решение работает, оно серьёзно влияет на производительность. Каждый раз, когда вы переназначаете ItemsSourceListBox новому объекту, ListBox сначала сбрасывает предыдущие элементы и повторно создает весь список. Влияние производительности увеличится, если ListBox сопоставляется со сложным DataTemplate.
Очень эффективное решение этой проблемы заключается в том, чтобы сделать список сотрудников ObservableCollection<T>. Объект ObservableCollection<T> вызывает уведомление об изменении, которое может получить модуль привязки данных. Событие добавляет или удаляет элемент из ItemsControl без необходимости повторного создания всего списка.
В таблице ниже показано время, затраченное на обновление ListBox (с отключенной виртуализацией пользовательского интерфейса) при добавлении одного элемента. Число в первой строке представляет истекшее время, когда объект CLRList<T> привязан к ListBox элемента ItemsSource. Число во второй строке обозначает время, прошедшее с момента, когда ObservableCollection<T> связывается с ListBoxэлемента ItemsSource. Обратите внимание на значительные экономии времени с помощью стратегии привязки данных ObservableCollection<T>.
Привязка данных для ItemsSource | время обновления для 1 элемента (мс) |
---|---|
К объекту CLRList<T> | 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, если единственной целью является привязка данных.
См. также
- Оптимизация производительности приложения WPF
- планирование производительности приложений
- Использование преимуществ аппаратного обеспечения
- Макет и дизайн
- 2D графика и изображения
- поведение объектов
- Ресурсы приложения
- текст
- другие рекомендации по производительности
- Обзор привязки данных
- Пошаговое руководство: кэширование данных приложения в приложении WPF
.NET Desktop feedback