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.

FreezableChanged提供事件,以通知觀察者對物件的任何修改。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也可以線上程之間共用,而無法凍結FreezableA 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.

使用 FreezableUsing 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時,動畫系統會自動建立凍結物件的可修改複本。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.

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:

  • 在讀取非相依性屬性資料成員的任何 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.)

  • 先呼叫WritePostscript方法,再結束寫入非相依性屬性資料成員的方法。Call the WritePostscript method before exiting methods that write to non-dependency property data members.

如果您的類別包含屬於DependencyObject物件的非相依性屬性資料成員,則您也必須在每次變更其中一個值時OnFreezablePropertyChanged呼叫方法,即使您要將成員設定為null也一樣。If 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