Freezable 对象概述Freezable Objects Overview

本主题介绍如何有效地使用和创建Freezable对象, 这些对象提供有助于提高应用程序性能的特殊功能。This topic describes how to effectively use and create Freezable objects, which provide special features that can help improve application performance. 被冻结对象的示例包括画笔、笔、转换、几何图形和动画。Examples of freezable objects include brushes, pens, transformations, geometries, and animations.

什么是可冻结的?What Is a Freezable?

Freezable是具有两种状态的特殊对象类型: 解冻和冻结。A Freezable is a special type of object that has two states: unfrozen and frozen. 解冻后, 的Freezable行为与任何其他对象的行为类似。When unfrozen, a Freezable appears to behave like any other object. 冻结后, 将Freezable无法再修改。When frozen, a Freezable can no longer be modified.

Freezable 提供事件来通知观察者对Changed对象的任何修改。A Freezable provides a Changed event to notify observers of any modifications to the object. Freezable冻结会提高其性能, 因为它不再需要在更改通知上消耗资源。Freezing a Freezable can improve its performance, because it no longer needs to spend resources on change notifications. 冻结Freezable还可在线程间共享, 而Freezable不能冻结。A frozen Freezable can also be shared across threads, while an unfrozen Freezable cannot.

尽管类有许多应用程序, 但FreezableWindows Presentation Foundation (WPF)Windows Presentation Foundation (WPF)的大多数对象均与图形子系统相关。 FreezableAlthough the Freezable class has many applications, most Freezable objects in Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF) are related to the graphics sub-system.

使用Freezable类可以更轻松地使用某些图形系统对象, 并且可以帮助提高应用程序性能。The Freezable class makes it easier to use certain graphics system objects and can help improve application performance. 继承自Freezable的类型的示例Brush包括、 TransformGeometry类。Examples of types that inherit from Freezable include the Brush, Transform, and Geometry classes. 由于它们包含非托管资源, 因此, 系统必须监视这些对象进行修改, 然后在对原始对象进行更改时更新其相应的非托管资源。Because they contain unmanaged resources, the system must monitor these objects for modifications, and then update their corresponding unmanaged resources when there is a change to the original object. 即使您不实际修改图形系统对象, 系统仍必须将它的一些资源用于监视对象, 以防您这样做更改。Even if you don't actually modify a graphics system object, the system must still spend some of its resources monitoring the object, in case you do change it.

例如, 假设您创建了一个SolidColorBrush画笔, 并使用它来绘制按钮的背景。For example, suppose you create a SolidColorBrush brush and use it to paint the background of a button.

Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);
myButton.Background = myBrush;  
Dim myButton As New Button()
Dim myBrush As New SolidColorBrush(Colors.Yellow)
myButton.Background = myBrush

呈现按钮时, WPFWPF图形子系统将使用您提供的信息来绘制一组像素来创建按钮的外观。When the button is rendered, the WPFWPF graphics sub-system uses the information you provided to paint a group of pixels to create the appearance of a button. 虽然您使用纯色画笔来说明如何绘制按钮, 但您的纯色画笔实际上不会执行绘制操作。Although you used a solid color brush to describe how the button should be painted, your solid color brush doesn't actually do the painting. 图形系统会为按钮和画笔生成快速、低级别的对象, 并且这些对象确实出现在屏幕上。The graphics system generates fast, low-level objects for the button and the brush, and it is those objects that actually appear on the screen.

如果要修改画笔, 则必须重新生成这些低级别对象。If you were to modify the brush, those low-level objects would have to be regenerated. 可冻结的类可让画笔查找其相应的已生成低级别对象并在更改时更新这些对象。The freezable class is what gives a brush the ability to find its corresponding generated, low-level objects and to update them when it changes. 启用此功能后, 画笔会被视为 "解冻"。When this ability is enabled, the brush is said to be "unfrozen."

可冻结的Freeze方法使您能够禁用此自我更新功能。A freezable's Freeze method enables you to disable this self-updating ability. 您可以使用此方法使画笔变为 "冻结" 或不可修改。You can use this method to make the brush become "frozen," or unmodifiable.

备注

并非每个可冻结的对象都可以冻结。Not every Freezable object can be frozen. 若要避免引发InvalidOperationException, 请检查可冻结对象的CanFreeze属性的值, 以确定它是否可以冻结, 然后再尝试将其冻结。To avoid throwing an InvalidOperationException, check the value of the Freezable object's CanFreeze property to determine whether it can be frozen before attempting to freeze it.

if (myBrush.CanFreeze)
{
    // Makes the brush unmodifiable.
    myBrush.Freeze();
}
If myBrush.CanFreeze Then
    ' Makes the brush unmodifiable.
    myBrush.Freeze()
End If

当你不再需要修改可冻结的时, 冻结它可提供性能优势。When you no longer need to modify a freezable, freezing it provides performance benefits. 如果在此示例中冻结了画笔, 则图形系统将不再需要监视其更改。If you were to freeze the brush in this example, the graphics system would no longer need to monitor it for changes. 图形系统还可以进行其他优化, 因为它知道画笔不会改变。The graphics system can also make other optimizations, because it knows the brush won't change.

备注

为方便起见, 可冻结对象保持解冻, 除非你显式冻结它们。For convenience, freezable objects remain unfrozen unless you explicitly freeze them.

使用可冻结对象Using Freezables

使用未冻结的可冻结对象与使用任何其他类型的对象类似。Using an unfrozen freezable is like using any other type of object. 在下面的示例中, 在用于绘制SolidColorBrush按钮背景后, 的颜色将从黄色更改为红色。In the following example, the color of a SolidColorBrush is changed from yellow to red after it's used to paint the background of a button. 图形系统在幕后工作, 在下次刷新屏幕时, 自动将按钮从黄色更改为红色。The graphics system works behind the scenes to automatically change the button from yellow to red the next time the screen is refreshed.

Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);
myButton.Background = myBrush;  


// Changes the button's background to red.
myBrush.Color = Colors.Red;
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

冻结冻结Freezing a Freezable

若要使Freezable其成为不可修改的Freeze , 请调用其方法。To make a Freezable unmodifiable, you call its Freeze method. 冻结包含可冻结对象的对象时, 这些对象也会被冻结。When you freeze an object that contains freezable objects, those objects are frozen as well. 例如, 如果冻结PathGeometry, 则它包含的图形和段也将被冻结。For example, if you freeze a PathGeometry, the figures and segments it contains would be frozen too.

如果满足以下任一条件, 则无法冻结可冻结的:A Freezable can't be frozen if any of the following are true:

  • 它具有动画或数据绑定属性。It has animated or data bound properties.

  • 它包含动态资源设置的属性。It has properties set by a dynamic resource. (有关动态资源的详细信息, 请参阅XAML 资源。)(See the XAML Resources for more information about dynamic resources.)

  • 它包含Freezable无法冻结的子对象。It contains Freezable sub-objects that can't be frozen.

如果这些条件为 false, 并且你不打算修改Freezable, 则应该冻结它以获得前面所述的性能优势。If these conditions are false, and you don't intend to modify the Freezable, then you should freeze it to gain the performance benefits described earlier.

调用可冻结的Freeze方法后, 将无法再对其进行修改。Once you call a freezable's Freeze method, it can no longer be modified. 尝试修改冻结对象将导致InvalidOperationException引发。Attempting to modify a frozen object causes an InvalidOperationException to be thrown. 下面的代码引发异常, 因为我们尝试在冻结画笔之后修改画笔。The following code throws an exception, because we attempt to modify the brush after it's been frozen.


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());
}


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

若要避免引发此异常, 可以使用IsFrozen方法来确定Freezable是否已冻结。To avoid throwing this exception, you can use the IsFrozen method to determine whether a Freezable is frozen.


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;
}



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


在上面的代码示例中, 使用Clone方法对冻结的对象创建了一个可修改的副本。In the preceding code example, a modifiable copy was made of a frozen object using the Clone method. 下一部分更详细地讨论了克隆。The next section discusses cloning in more detail.

注意由于不能对冻结的可冻结对象进行动画处理, 因此当你尝试Freezable Storyboard使用对它们进行动画处理时, 动画系统将自动创建冻结对象的可修改复本。Note Because a frozen freezable cannot be animated, the animation system will automatically create modifiable clones of frozen Freezable objects when you try to animate them with a Storyboard. 若要消除克隆导致的性能开销, 请在要对对象进行动画处理时使对象保持解冻。To eliminate the performance overhead caused by cloning, leave an object unfrozen if you intend to animate it. 有关利用情节提要进行动画处理的详细信息, 请参阅情节提要概述For more information about animating with storyboards, see the Storyboards Overview.

从标记冻结Freezing from Markup

若要冻结Freezable在标记中声明的对象, 请PresentationOptions:Freeze使用特性。To freeze a Freezable object declared in markup, you use the PresentationOptions:Freeze attribute. 在下面的示例中, SolidColorBrush将声明为页资源并冻结。In the following example, a SolidColorBrush is declared as a page resource and frozen. 然后, 将使用它来设置按钮的背景。It is then used to set the background of a button.

<Page 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" 
  xmlns:mc="http://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属性, 必须映射到表示选项命名空间:。 http://schemas.microsoft.com/winfx/2006/xaml/presentation/optionsTo use the Freeze attribute, you must map to the presentation options namespace: http://schemas.microsoft.com/winfx/2006/xaml/presentation/options. PresentationOptions建议用于映射此命名空间的前缀:PresentationOptions is the recommended prefix for mapping this namespace:

xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"   

由于并非所有 XAML 读取器都能识别此特性, 因此建议使用mc: 可忽略属性Presentation:Freeze属性标记为可忽略:Because not all XAML readers recognize this attribute, it's recommended that you use the mc:Ignorable Attribute to mark the Presentation:Freeze attribute as ignorable:

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
mc:Ignorable="PresentationOptions"  

有关详细信息, 请参阅mc: 忽略属性页。For more information, see the mc:Ignorable Attribute page.

"解冻""Unfreezing" a Freezable

一旦冻结, 就Freezable永远不能对其进行修改或取消冻结; 不过, 可以Clone使用或CloneCurrentValue方法创建未冻结的克隆。Once frozen, a Freezable can never be modified or unfrozen; however, you can create an unfrozen clone using the Clone or CloneCurrentValue method.

在下面的示例中, 按钮的背景是使用画笔设置的, 然后该画笔会被冻结。In the following example, the button's background is set with a brush and that brush is then frozen. 使用Clone方法对画笔生成了未冻结的副本。An unfrozen copy is made of the brush using the Clone method. 将修改克隆, 并使用它将按钮的背景从黄色更改为红色。The clone is modified and used to change the button's background from yellow to red.

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;
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

备注

不管使用哪种克隆方法, 动画永远都不会复制到新Freezable的。Regardless of which clone method you use, animations are never copied to the new Freezable.

CloneCloneCurrentValue方法会生成一个已冻结的深层副本。The Clone and CloneCurrentValue methods produce deep copies of the freezable. 如果可冻结的包含其他冻结的可冻结对象, 则它们也会被克隆, 并可进行修改。If the freezable contains other frozen freezable objects, they are also cloned and made modifiable. 例如, 如果克隆冻结PathGeometry的以使其可修改, 则还会复制其包含的图形和线段, 并使其成为可修改的。For example, if you clone a frozen PathGeometry to make it modifiable, the figures and segments it contains are also copied and made modifiable.

创建自己的有冻结类Creating Your Own Freezable Class

派生自Freezable的类具有以下功能。A class that derives from Freezable gains the following features.

  • 特殊状态: 只读 (冻结) 和可写状态。Special states: a read-only (frozen) and a writable state.

  • 线程安全: 冻结Freezable可以在线程之间共享。Thread safety: a frozen Freezable can be shared across threads.

  • 详细更改通知:与其他DependencyObject不同, 可冻结对象会在子属性值更改时提供更改通知。Detailed change notification: Unlike other DependencyObjects, Freezable objects provide change notifications when sub-property values change.

  • 轻松克隆: 可冻结的类已经实现了几种生成深层克隆的方法。Easy cloning: the Freezable class has already implemented several methods that produce deep clones.

是的一DependencyObject种类型, 因此使用了依赖属性系统。 FreezableA Freezable is a type of DependencyObject, and therefore uses the dependency property system. 类属性不一定是依赖属性, 但使用依赖属性将减少您必须编写的代码量, 因为Freezable该类是使用依赖属性设计的。Your class properties don't have to be dependency properties, but using dependency properties will reduce the amount of code you have to write, because the Freezable class was designed with dependency properties in mind. 有关依赖属性系统的详细信息, 请参阅依赖属性概述For more information about the dependency property system, see the Dependency Properties Overview.

Freezable个子类必须CreateInstanceCore重写方法。Every Freezable subclass must override the CreateInstanceCore method. 如果你的类对所有数据使用依赖属性, 则你已完成。If your class uses dependency properties for all its data, you're finished.

如果类包含非依赖属性数据成员, 还必须重写以下方法:If your class contains non-dependency property data members, you must also override the following methods:

还必须遵守以下规则, 以便访问和写入不是依赖属性的数据成员:You must also observe the following rules for accessing and writing to data members that are not dependency properties:

  • 在读取非依赖属性数据成员的任何 API 的开头, 调用ReadPreamble方法。At the beginning of any API that reads non-dependency property data members, call the ReadPreamble method.

  • 在写入非依赖属性数据成员的任何 API 的开头, 请调用WritePreamble方法。At the beginning of any API that writes non-dependency property data members, call the WritePreamble method. (在 API 中调用WritePreamble后, ReadPreamble如果还读取非依赖属性数据成员, 则无需额外调用。)(Once you've called WritePreamble in an API, you don't need to make an additional call to ReadPreamble if you also read non-dependency property data members.)

  • 在退出写入非依赖属性数据成员的方法之前调用方法。WritePostscriptCall the WritePostscript method before exiting methods that write to non-dependency property data members.

如果类包含非依赖属性数据成员 (这些对象是DependencyObject对象), 则在每次更改其值时, 您还必须OnFreezablePropertyChanged调用方法, 即使您要将成员设置为nullIf your class contains non-dependency-property data members that are DependencyObject objects, you must also call the OnFreezablePropertyChanged method each time you change one of their values, even if you're setting the member to null.

备注

使用对基实现的调用来开始Freezable重写的每个方法非常重要。It's very important that you begin each Freezable method you override with a call to the base implementation.

有关自定义Freezable类的示例, 请参阅自定义动画示例For an example of a custom Freezable class, see the Custom Animation Sample.

请参阅See also