Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Понимание встроенного поведения объектов WPF поможет вам сделать правильные компромиссы между функциональными возможностями и производительностью.
Не удаляя обработчики событий у объектов, вы можете предотвратить их удаление из памяти.
Делегат, который объект передает своему событию, фактически является ссылкой на этот объект. Поэтому обработчики событий могут сохранять объекты в живых дольше, чем ожидалось. При очистке объекта, зарегистрированного на прослушивание события другого объекта, важно удалить делегата, прежде чем освободить объект. Сохранение ненужных объектов в живых увеличивает использование памяти приложения. Это особенно верно, если объект является корнем логического дерева или визуального дерева.
WPF представляет слабый шаблон прослушивателя событий для событий, которые могут быть полезны в ситуациях, когда связи времени существования объекта между источником и прослушивателем трудно отслеживать. Некоторые существующие события WPF используют этот шаблон. Если вы реализуете объекты с пользовательскими событиями, этот шаблон может использоваться для вас. Дополнительные сведения см. в разделе "Слабые шаблоны событий".
Существует несколько средств, таких как CLR Profiler и средство просмотра рабочих наборов, которые могут содержать сведения об использовании памяти указанного процесса. Профилировщик CLR включает в себя ряд очень полезных видов профиля выделения, включая гистограмму выделенных типов, графы выделения и вызовов, диаграмму, отражающую сборки мусора различных поколений и итоговое состояние управляемой кучи после выполнения этих сборок, а также дерево вызовов, показывающее выделение и нагрузки сборок для каждого метода. Дополнительные сведения см. в разделе "Производительность".
Свойства зависимостей и объекты
Как правило, доступ к свойству зависимости объекта DependencyObject не медленнее, чем доступ к свойству CLR. Хотя для задания значения свойства существует небольшая нагрузка на производительность, получение значения выполняется так быстро, как и при получении значения из свойства CLR. Несмотря на небольшие затраты на производительность, свойства зависимостей поддерживают такие надежные функции, как привязка данных, анимация, наследование и стилизация. Дополнительные сведения см. в разделе Обзор свойств зависимостей.
Оптимизация зависимостейProperty
Необходимо тщательно определить свойства зависимостей в приложении. Если ваш DependencyProperty влияет только на параметры метаданных типа отрисовки, а не на другие параметры метаданных, такие как AffectsMeasure, вы должны отметить это, переопределив соответствующие метаданные. Дополнительные сведения о переопределении или получении метаданных свойства зависимости см. в .
Может быть более эффективно, если обработчик изменений свойств вручную аннулирует процессы измерения, компоновки и отрисовки, когда не все изменения свойств на них влияют. Например, можно повторно отобразить фон только в том случае, если значение больше заданного предела. В этом случае обработчик изменений свойств обеспечивает недействительность рендеринга только в том случае, если значение превышает заданное ограничение.
Создание наследуемого объекта DependencyProperty не является бесплатным
По умолчанию зарегистрированные свойства зависимостей не наследуются. Однако можно явно сделать любое свойство наследуемым. Хотя это полезная функция, преобразование свойства в наследуемое влияет на производительность, увеличивая время на недействительность свойства.
Тщательно используйте RegisterClassHandler
При вызове RegisterClassHandler можно сохранить состояние экземпляра, важно учитывать, что обработчик вызывается на каждом экземпляре, что может привести к проблемам с производительностью. Используйте RegisterClassHandler только в том случае, если вашему приложению требуется сохранять состояние экземпляра.
Задайте значение по умолчанию для DependencyProperty при регистрации
При создании DependencyProperty , требующего значения по умолчанию, задайте значение с помощью метаданных по умолчанию, передаваемых в качестве параметра методу RegisterDependencyProperty. Используйте эту технику, а не устанавливайте значение свойства в конструкторе или каждом экземпляре элемента.
Задайте значение PropertyMetadata с помощью Register
При создании DependencyProperty у вас есть возможность задать PropertyMetadata с помощью методов Register или OverrideMetadata. Хотя объект может иметь статический конструктор для вызова OverrideMetadata, это не оптимальное решение и будет влиять на производительность. Для обеспечения оптимальной производительности задайте PropertyMetadata во время вызова Register.
Замораживаемые объекты
A Freezable — это особый тип объекта, который имеет два состояния: не заморожено и заморожено. Замораживание объектов, когда это возможно, повышает производительность приложения и уменьшает его рабочий набор. Для получения дополнительной информации см. Обзор замораживаемых объектов.
Каждый Freezable имеет событие Changed, которое возникает при изменении. Однако уведомления об изменениях являются дорогостоящими с точки зрения производительности приложений.
Рассмотрим следующий пример, в котором каждый Rectangle использует один и тот же объект Brush.
rectangle_1.Fill = myBrush;
rectangle_2.Fill = myBrush;
rectangle_3.Fill = myBrush;
// ...
rectangle_10.Fill = myBrush;
rectangle_1.Fill = myBrush
rectangle_2.Fill = myBrush
rectangle_3.Fill = myBrush
' ...
rectangle_10.Fill = myBrush
По умолчанию WPF предоставляет обработчик событий для события объекта SolidColorBrush, чтобы сделать недействительным свойство Changed объекта Rectangle. В этом случае каждый раз, когда SolidColorBrush должно срабатывать событие Changed, необходимо вызывать функцию обратного вызова для каждого Rectangle—многократные вызовы этих функций налагают значительное снижение производительности. Кроме того, добавление и удаление обработчиков на данном этапе требует значительных ресурсов, так как приложению придется пройти весь список, чтобы выполнить эту задачу. Если сценарий приложения никогда не изменяет SolidColorBrush, вы будете платить за обслуживание Changed обработчиков событий без необходимости.
Замораживание Freezable может улучшить его производительность, так как больше не требуется тратить ресурсы на поддержание уведомлений об изменениях. В таблице ниже показан размер простого SolidColorBrush, когда его свойство IsFrozen установлено в true
, по сравнению с тем, когда оно не установлено. Это подразумевает применение одной кисти к свойству Fill у десяти объектов Rectangle.
Государство | размера |
---|---|
Замороженный SolidColorBrush | 212 Байт |
Не замороженное SolidColorBrush | 972 Байт |
В следующем примере кода демонстрируется эта концепция:
Brush frozenBrush = new SolidColorBrush(Colors.Blue);
frozenBrush.Freeze();
Brush nonFrozenBrush = new SolidColorBrush(Colors.Blue);
for (int i = 0; i < 10; i++)
{
// Create a Rectangle using a non-frozed Brush.
Rectangle rectangleNonFrozen = new Rectangle();
rectangleNonFrozen.Fill = nonFrozenBrush;
// Create a Rectangle using a frozed Brush.
Rectangle rectangleFrozen = new Rectangle();
rectangleFrozen.Fill = frozenBrush;
}
Dim frozenBrush As Brush = New SolidColorBrush(Colors.Blue)
frozenBrush.Freeze()
Dim nonFrozenBrush As Brush = New SolidColorBrush(Colors.Blue)
For i As Integer = 0 To 9
' Create a Rectangle using a non-frozed Brush.
Dim rectangleNonFrozen As New Rectangle()
rectangleNonFrozen.Fill = nonFrozenBrush
' Create a Rectangle using a frozed Brush.
Dim rectangleFrozen As New Rectangle()
rectangleFrozen.Fill = frozenBrush
Next i
Измененные обработчики в размороженных объектах, поддерживающих заморозку, могут не давать объектам завершиться.
Делегат, который объект передает событию объекта Freezable, фактически является ссылкой на этот объект Changed. Changed Поэтому обработчики событий могут сохранять объекты в живых дольше, чем ожидалось. При выполнении очистки объекта, зарегистрированного для прослушивания Freezable события объекта Changed , необходимо удалить этот делегат перед освобождением объекта.
WPF также подключает Changed события внутри системы. Например, все свойства зависимостей, которые принимают Freezable в качестве значения, будут автоматически прослушивать Changed события. Свойство Fill , которое принимает значение Brush, иллюстрирует эту концепцию.
Brush myBrush = new SolidColorBrush(Colors.Red);
Rectangle myRectangle = new Rectangle();
myRectangle.Fill = myBrush;
Dim myBrush As Brush = New SolidColorBrush(Colors.Red)
Dim myRectangle As New Rectangle()
myRectangle.Fill = myBrush
При назначении myBrush
на myRectangle.Fill
, делегат, указывающий на объект Rectangle, будет добавлен в событие SolidColorBrush объекта Changed. Это означает, что следующий код фактически не делает myRect
пригодным для сборки мусора.
myRectangle = null;
myRectangle = Nothing
В этом случае myBrush
по-прежнему поддерживает myRectangle
в рабочем состоянии и возвратится к нему, когда произойдет его Changed событие. Обратите внимание, что назначение myBrush
в свойство Fill нового Rectangle просто добавит другой обработчик событий для myBrush
.
Рекомендуемый способ очистки этих типов объектов — это удалить Brush из свойства Fill, что, в свою очередь, приведет к удалению обработчика событий Changed.
myRectangle.Fill = null;
myRectangle = null;
myRectangle.Fill = Nothing
myRectangle = Nothing
Виртуализация пользовательского интерфейса
WPF также предоставляет вариант элемента StackPanel, который автоматически виртуализирует дочернее содержимое, привязанное к данным. В этом контексте слово virtualize относится к методу, через который подмножество объектов создается из большего количества элементов данных на основе их видимости на экране. Генерация большого количества элементов пользовательского интерфейса затратно по ресурсам, как по памяти, так и по процессору, когда на экране могут находиться только несколько элементов в определенное время. VirtualizingStackPanel (через функциональные возможности, предоставляемые VirtualizingPanel) вычисляет видимые элементы и работает с ItemContainerGenerator из ItemsControl (например, ListBox или ListView) только для создания элементов для видимых элементов.
В рамках оптимизации производительности визуальные объекты для этих элементов создаются или остаются активными, только если они отображаются на экране. Если они больше не находятся в просматриваемой области элемента управления, визуальные объекты могут быть удалены. Это не следует путать с виртуализацией данных, где объекты данных не присутствуют полностью в локальной коллекции, а передаются в потоке по мере необходимости.
В таблице ниже показано затраченное время на добавление и отрисовку 5000 TextBlock элементов в StackPanel и VirtualizingStackPanel. В этом сценарии измерения представляют время между присоединением текстовой ItemsSource строки к ItemsControl свойству объекта к времени, когда элементы панели отображают текстовую строку.
Панель хоста | Время отрисовки (мс) |
---|---|
StackPanel | 3210 |
VirtualizingStackPanel | 46 |
См. также
.NET Desktop feedback