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. Freezable 对象的示例包括画笔、 笔、 转换、 几何和动画。Examples of freezable objects include brushes, pens, transformations, geometries, and animations.

什么是 Freezable?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.

尽管Freezable类具有许多应用程序,最Freezable中的对象Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF)与图形子系统相关。Although 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包括BrushTransform,和Geometry类。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. Freezable 类是什么使画笔能够以查找其相应的生成的低级别对象,并且它发生更改时更新它们。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."

Freezable 的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.

备注

不是每个 Freezable 对象可以被冻结。Not every Freezable object can be frozen. 若要避免引发InvalidOperationException,检查 Freezable 对象的值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

当不再需要进行修改的 freezable 时,冻结它提供性能优势。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.

备注

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

使用的可冻结对象Using Freezables

使用解冻 freezable 就像使用任何其他类型的对象。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

冻结 FreezableFreezing a Freezable

若要使Freezable变为不可修改,则调用其Freeze方法。To make a Freezable unmodifiable, you call its Freeze method. 冻结包含 freezable 对象的对象,这些对象也会冻结起来。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.

Freezable不能被冻结,如果以下任何条件成立: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.

一旦调用 freezable 的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 不能进行动画处理时,动画系统将自动创建的可修改克隆冻结Freezable对象时尝试与它们进行动画处理StoryboardNote 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: Ignorable 特性标记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: Ignorable 特性页。For more information, see the mc:Ignorable Attribute page.

"解冻"Freezable"Unfreezing" a Freezable

一次冻结Freezable永远不会修改或解冻; 但是,可以创建使用一个未冻结的克隆CloneCloneCurrentValue方法。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

备注

无论使用哪种克隆方法,动画不会被复制到新FreezableRegardless 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. 如果 freezable 包含其他冻结 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.

创建您自己的 Freezable 类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.

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

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

一个Freezable是一种DependencyObject,因此使用依赖项属性系统。A 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:

  • 在任何开头APIAPI读取非依赖项属性数据成员,请调用ReadPreamble方法。At the beginning of any APIAPI 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. (调用后WritePreambleAPIAPI,不需要进行额外调用ReadPreamble如果还读取非依赖项属性数据成员。)(Once you've called WritePreamble in an APIAPI, you don't need to make an additional call to ReadPreamble if you also read non-dependency property data members.)

  • 调用WritePostscript方法,然后再退出写入非依赖项属性数据成员的方法。Call 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