Общие сведения об объектах класса Freezable
В данном разделе описано, как эффективно использовать и создавать объекты Freezable, которые обеспечивают специальные возможности, помогающие повысить производительность приложения. Примерами объектов класса Freezable являются кисти, перья, преобразования, геометрия объектов и анимация.
В этом разделе содержатся следующие подразделы.
Понятие объекта Freezable
Freezable представляет сосбой особый тип объекта, имеющий два состояния: фиксированное и нефиксированное. Незафиксированный объект Freezable ведет себя как любой другой объект. Зафиксированный объект Freezable нельзя изменить.
Класс Freezable предоставляет событие Changed для уведомления наблюдающих объектов обо всех изменениях объекта. Фиксация объекта Freezable может повысить его производительность, поскольку больше не потребуется тратить ресурсы на уведомления об изменениях. Зафиксированные объекты Freezable также могут совместно использоваться потоками, в отличие от незафиксированных Freezable.
Хотя класс Freezable имеет много приложений, большинство объектов Freezable в приложении Windows Presentation Foundation (WPF) связаны с графической подсистемой.
Класс Freezable упрощает использование определенных объектов графических систем и помогает повысить быстродействие приложения. Примерами типов, наследуемых от класса Freezable, являются классы Brush, Transform и Geometry. Так как они содержат неуправляемые ресурсы, система должна отслеживать изменения этих объектов и при наличии изменений исходного объекта обновлять соответствующие им неуправляемые ресурсы. Даже если объект графической системы на самом деле не изменяется, то система все равно должна потратить ресурсы на наблюдение за объектом, если над ним выполняются некоторые действия.
Например, при создании кисти SolidColorBrush и использовании ее для формирования фона кнопки.
Dim myButton As New Button()
Dim myBrush As New SolidColorBrush(Colors.Yellow)
myButton.Background = myBrush
Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);
myButton.Background = myBrush;
При прорисовке кнопки графическая подсистема WPF использует предоставленные пользователем сведения для закраски группы точек, чтобы задать внешний вид кнопки. Хотя пользователь использует заливку сплошным цветом для описания внешнего вида кнопки, фактически не она выполняет закраску. Графическая система создает быстрые низкоуровневые объекты для кнопки и кисти, и именно эти объекты фактически отображаются на экране.
При изменении кисти эти низкоуровневые объекты необходимо обновлять. Именно класс Freezable дает кисти возможность найти соответствующие ей низкоуровневые объекты и обновить их, когда она изменяется. Если эта возможность включена, кисть считается "незафиксированной".
Метод Freezable Freeze позволяет отключить данную возможность самостоятельного обновления. Этот метод позволяет "зафиксировать" кисть, т.е. сделать ее неизменяемой.
Примечание |
---|
Не каждый объект Freezable может быть зафиксирован.Чтобы избежать возникновения исключения InvalidOperationException, перед фиксированием объекта необходимо предварительно проверить значение свойства CanFreeze объекта Freezable, чтобы определить, может ли он быть зафиксирован. |
If myBrush.CanFreeze Then
' Makes the brush unmodifiable.
myBrush.Freeze()
End If
if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}
Когда больше не требуется изменять Freezable, фиксирование объекта дает выигрыш в производительности. Если бы кисть в данном примере была зафиксирована, то графической системе больше не понадобилось бы отслеживать ее изменения. Графическая система также может выполнять другие виды оптимизации, так как известно, что кисть не будет изменяться.
Примечание |
---|
Для удобства объекты Freezable остаются незафиксированными, пока вы не зафиксируете их явным образом. |
Использование объектов Freezable
Использование незафиксированного объекта Freezable аналогично использованию любого другого типа объектов. В следующем примере цвет объекта SolidColorBrush изменяется с желтого на красный после того, как он используется для закраски фона кнопки. Графическая система работает в фоновом режиме, чтобы автоматически изменить цвет кнопки с желтого на красный при следующем обновлении экрана.
Dim myButton As New Button()
Dim myBrush As New SolidColorBrush(Colors.Yellow)
myButton.Background = myBrush
' Changes the button's background to red.
myBrush.Color = Colors.Red
Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);
myButton.Background = myBrush;
// Changes the button's background to red.
myBrush.Color = Colors.Red;
Фиксация объекта класса Freezable
Чтобы сделать объект Freezable неизменяемым, необходимо вызвать его метод Freeze. При фиксировании объекта, содержащего объекты Freezable, вложенные объекты также фиксируются. Например, если зафиксировать объект PathGeometry, содержащиеся в нем фигуры и сегменты также будут зафиксированы.
Freezable нельзя зафиксировать при выполнении одного из следующих условий:
Объект имеет свойства анимации или привязки данных.
У объекта есть свойства, заданные динамическим ресурсом. Дополнительные сведения о динамических ресурсах см. в разделе Общие сведения о ресурсах.
Он содержит подобъекты Freezable, которые нельзя зафиксировать.
Если не выполняется ни одно из этих условий и не требуется изменять объект Freezable, его стоит зафиксировать, чтобы получить описанный выше выигрыш в производительности.
Объект Freezable не может быть изменен после вызова его метода Freeze. При попытке изменения зафиксированного объекта возникает исключение InvalidOperationException. Следующий код вызывает исключение, поскольку выполняется попытка изменить кисть после того, как она была зафиксирована.
Dim myButton As New Button()
Dim myBrush As New SolidColorBrush(Colors.Yellow)
If myBrush.CanFreeze Then
' Makes the brush unmodifiable.
myBrush.Freeze()
End If
myButton.Background = myBrush
Try
' Throws an InvalidOperationException, because the brush is frozen.
myBrush.Color = Colors.Red
Catch ex As InvalidOperationException
MessageBox.Show("Invalid operation: " & ex.ToString())
End Try
Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);
if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}
myButton.Background = myBrush;
try {
// Throws an InvalidOperationException, because the brush is frozen.
myBrush.Color = Colors.Red;
}catch(InvalidOperationException ex)
{
MessageBox.Show("Invalid operation: " + ex.ToString());
}
Чтобы избежать возникновения этого исключения, можно использовать метод IsFrozen, чтобы определить, зафиксирован ли объект Freezable.
Dim myButton As New Button()
Dim myBrush As New SolidColorBrush(Colors.Yellow)
If myBrush.CanFreeze Then
' Makes the brush unmodifiable.
myBrush.Freeze()
End If
myButton.Background = myBrush
If myBrush.IsFrozen Then ' Evaluates to true.
' If the brush is frozen, create a clone and
' modify the clone.
Dim myBrushClone As SolidColorBrush = myBrush.Clone()
myBrushClone.Color = Colors.Red
myButton.Background = myBrushClone
Else
' If the brush is not frozen,
' it can be modified directly.
myBrush.Color = Colors.Red
End If
Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);
if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}
myButton.Background = myBrush;
if (myBrush.IsFrozen) // Evaluates to true.
{
// If the brush is frozen, create a clone and
// modify the clone.
SolidColorBrush myBrushClone = myBrush.Clone();
myBrushClone.Color = Colors.Red;
myButton.Background = myBrushClone;
}
else
{
// If the brush is not frozen,
// it can be modified directly.
myBrush.Color = Colors.Red;
}
В предыдущем примере кода с помощью метода Clone была получена изменяемая копия зафиксированного объекта. В следующем разделе клонирование рассматривается более подробно.
Замечание Поскольку зафиксированный объект Freezable не может быть анимирован, система анимации автоматически создаст изменяемые копии зафиксированных объектов Freezable при попытке их анимации с помощью Storyboard. Чтобы снизить накладные расходы, связанные с клонированием, оставьте объект незафиксированным, если потребуется его анимировать. Дополнительные сведения об анимации с помощью Storyboard см. в разделе Общие сведения о Storyboard.
Фиксирование объектов из разметки
Чтобы зафиксировать объект Freezable, объявленный в разметке, используйте атрибут PresentationOptions:Freeze. В следующем примере SolidColorBrush объявляется как ресурс страницы и фиксируется. Затем она используется для задания фона кнопки.
<Page
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
xmlns:PresentationOptions="https://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="PresentationOptions">
<Page.Resources>
<!-- This resource is frozen. -->
<SolidColorBrush
x:Key="MyBrush"
PresentationOptions:Freeze="True"
Color="Red" />
</Page.Resources>
<StackPanel>
<Button Content="A Button"
Background="{StaticResource MyBrush}">
</Button>
</StackPanel>
</Page>
Для использования атрибута Freeze необходимо сопоставить с параметрами представления пространство имен: https://schemas.microsoft.com/winfx/2006/xaml/presentation/options. PresentationOptions является рекомендуемым префиксом для сопоставления пространства имен:
xmlns:PresentationOptions="https://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
Так как не все средства чтения XAML распознают этот атрибут, рекомендуется использовать Атрибут mc: Ignorable, чтобы пометить атрибут Presentation:Freeze как некритический:
xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="PresentationOptions"
Дополнительные сведения см. на странице Атрибут mc: Ignorable.
Отмена фиксации объекта класса Freezable
После фиксации объект Freezable нельзя изменить или снять состояние фиксации. Однако можно создать незафиксированную копию с помощью метода Clone или метода CloneCurrentValue.
В следующем примере фон кнопки закрашивается кистью и затем кисть фиксируется. Незафиксированная копия кисти получается с помощью метода Clone. Копия изменяется и используется для изменения фона кнопки с желтого на красный.
Dim myButton As New Button()
Dim myBrush As New SolidColorBrush(Colors.Yellow)
' Freezing a Freezable before it provides
' performance improvements if you don't
' intend on modifying it.
If myBrush.CanFreeze Then
' Makes the brush unmodifiable.
myBrush.Freeze()
End If
myButton.Background = myBrush
' If you need to modify a frozen brush,
' the Clone method can be used to
' create a modifiable copy.
Dim myBrushClone As SolidColorBrush = myBrush.Clone()
' Changing myBrushClone does not change
' the color of myButton, because its
' background is still set by myBrush.
myBrushClone.Color = Colors.Red
' Replacing myBrush with myBrushClone
' makes the button change to red.
myButton.Background = myBrushClone
Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);
// Freezing a Freezable before it provides
// performance improvements if you don't
// intend on modifying it.
if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}
myButton.Background = myBrush;
// If you need to modify a frozen brush,
// the Clone method can be used to
// create a modifiable copy.
SolidColorBrush myBrushClone = myBrush.Clone();
// Changing myBrushClone does not change
// the color of myButton, because its
// background is still set by myBrush.
myBrushClone.Color = Colors.Red;
// Replacing myBrush with myBrushClone
// makes the button change to red.
myButton.Background = myBrushClone;
Примечание |
---|
Вне зависимости от выбора метода клонирования, анимация никогда не копируется в новый объект Freezable. |
Методы Clone и CloneCurrentValue создают детальные копии объекта Freezable. Если объект Freezable содержит другие зафиксированные объекты Freezable, они также копируются и становятся изменяемыми. Например, если копировать зафиксированный объект PathGeometry, чтобы сделать его изменяемым, содержащиеся в этом объекте фигуры и сегменты также копируются и становятся изменяемыми.
Создание собственного класса Freezable
Класс, производный от Freezable, поддерживает следующие функции:
Особые состояния: состояние только для чтения (фиксированное) и состояние только для записи.
Потокобезопасность: фиксированный объект Freezable можно использовать в нескольких потоках.
Подробные уведомления об изменениях: в отличие от других объектов DependencyObject, объекты Freezable сообщают об изменениях, если изменяются значения вложенных свойств.
Удобное клонирование: класс Freezable включает несколько уже реализованных методов, которые обеспечивают большую глубину клонирования.
Freezable представляет собой тип DependencyObject и поэтому использует систему свойств зависимости. Свойства класса не обязательно должны быть свойствами зависимости, но с помощью свойств зависимости объем кода, который нужно написать, сократится, так как класс Freezable был разработан с учетом свойств зависимости. Дополнительные сведения о системе свойств зависимости см. в разделе Общие сведения о свойствах зависимости.
Каждый подкласс Freezable должен переопределять метод CreateInstanceCore. Если класс использует свойства зависимости для всех своих данных, создание класса завершено.
Если класс содержит члены данных, не использующие свойство зависимости, необходимо также переопределить следующие методы:
Необходимо также соблюдать следующие правила для доступа и записи членов данных, которые не используют свойства зависимости:
В начале любого API, считывающего члены данных, не использующих свойство зависимости, вызовите метод ReadPreamble.
В начале любого API, записывающего члены данных, не использующие свойство зависимости, вызовите метод WritePreamble. (После вызова WritePreamble в API не требуется дополнительный вызов ReadPreamble, если также считываются члены данных, не использующие свойство зависимости.)
Вызовите метод WritePostscript перед выходом из методов, которые записывают члены данных, не использующие свойство зависимости.
Если класс содержит не поддерживающие свойство зависимости члены данных, являющиеся объектами DependencyObject, нужно также вызывать метод OnFreezablePropertyChanged при каждом изменении их значений, даже если члену задается значение null.
Примечание |
---|
Очень важно начинать каждый переопределяемый метод Freezable с вызова базовой реализации. |
Пример пользовательского класса Freezable см. на веб-странице Пример Custom Animation.
См. также
Ссылки
Основные понятия
Общие сведения о свойствах зависимости
Пользовательские свойства зависимостей