Freezable 物件概觀
本主題說明如何有效使用和建立 Freezable 物件,這些物件會提供可協助改善應用程式效能的特殊功能。 凍結物件的範例包括筆刷、畫筆、轉換、幾何和動畫。
什麼是可凍結的?
Freezable是一種特殊類型的物件,具有兩種狀態:凍結和凍結。 當凍結時, Freezable 看起來像任何其他物件一樣。 當凍結時, Freezable 無法再修改。
Freezable會提供 Changed 事件,以通知觀察者對物件所做的任何修改。 凍結 a Freezable 可以改善其效能,因為不再需要花費資源來變更通知。 凍結 Freezable 也可以線上程之間共用,但無法凍結 Freezable 。
Freezable雖然類別有許多應用程式,但是 Windows Presentation Foundation 中大部分 Freezable 的物件 (WPF) 與圖形子系統相關。
Freezable類別可讓您更輕鬆地使用特定圖形系統物件,並且有助於改善應用程式效能。 繼承自 Freezable 的類型範例包括 Brush 、 Transform 和 Geometry 類別。 因為它們包含未受管理的資源,所以系統必須監視這些物件以進行修改,然後在原始物件有變更時,更新其對應的非受控資源。 即使您不會實際修改圖形系統物件,系統仍然必須花一些資源來監視物件,以防您變更它。
例如,假設您建立 SolidColorBrush 筆刷,然後用它來繪製按鈕的背景。
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
當轉譯按鈕時,WPF 圖形子系統會使用您所提供的資訊來繪製一組圖元,以建立按鈕的外觀。 雖然您使用單色筆刷來描述按鈕的繪製方式,但您的純色筆刷實際上並不會進行繪製。 圖形系統會為按鈕和筆刷產生快速、低層級的物件,而這是實際顯示在畫面上的物件。
如果您要修改筆刷,則必須重新產生這些低層級的物件。 可凍結的類別可讓筆刷找出其對應的已產生、低層級的物件,並在變更時加以更新。 啟用這項功能時,筆刷稱為「未凍結」。
可凍結的 Freeze 方法可讓您停用此自我更新功能。 您可以使用這個方法,讓筆刷變成「凍結」或無法修改。
注意
並非每個可凍結的物件都可以凍結。 若要避免 InvalidOperationException 擲回,請檢查可凍結物件 CanFreeze 的屬性值,以判斷是否可以在嘗試凍結之前加以凍結。
if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}
If myBrush.CanFreeze Then
' Makes the brush unmodifiable.
myBrush.Freeze()
End If
當您不再需要修改可凍結時,凍結它可提供效能優勢。 如果您在此範例中凍結筆刷,圖形系統將不再需要監視它是否有變更。 圖形系統也可以進行其他優化,因為它知道筆刷不會變更。
注意
為了方便起見,可凍結的物件會保持未凍結,除非您明確凍結它們。
使用 Freezable
使用未凍結的可凍結類似于使用任何其他類型的物件。 在下列範例中,的色彩 SolidColorBrush 會在用來繪製按鈕的背景之後,從黃色變更為紅色。 圖形系統會在幕後運作,以在下次螢幕重新整理時,自動將按鈕從黃色變更為紅色。
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
凍結凍結
若要使 Freezable 無法修改,您可以呼叫其 Freeze 方法。 當您凍結包含可凍結物件的物件時,這些物件也會被凍結。 例如,如果您凍結 PathGeometry ,它所包含的資料和區段也會被凍結。
如果下列任一條件成立,則 無法 凍結凍結:
如果這些條件為 false,而您不想要修改 Freezable ,則應該凍結它以獲得稍早所述的效能優勢。
一旦您呼叫可凍結的 Freeze 方法之後,就無法再修改它。 嘗試修改凍結的物件會導致 InvalidOperationException 擲回。 下列程式碼會擲回例外狀況,因為我們會在凍結之後嘗試修改筆刷。
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 已凍結。
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 方法將已凍結的物件製作成可修改的複本。 下一節會更詳細地討論複製。
注意
由於凍結的可凍結無法進行動畫,因此當您嘗試以動畫顯示 Storyboard 時,動畫系統會自動建立已凍結 Freezable 物件的可修改複本。 為了消除複製所造成的效能負擔,如果您想要以動畫顯示物件,請將物件保持未凍結。 如需使用分鏡腳本進行動畫的詳細資訊,請參閱分鏡腳本 總覽。
從標記凍結
若要凍結標記中宣告的 Freezable 物件,請使用 PresentationOptions:Freeze
屬性。 在下列範例中, SolidColorBrush 會將宣告為頁面資源並凍結。 然後,它會用來設定按鈕的背景。
<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/options
。 PresentationOptions
是對應此命名空間的建議前置詞:
xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
由於並非所有的 XAML 讀取器都會辨識此屬性,建議您使用 mc:可忽略屬性 將屬性標示 Presentation:Freeze
為可忽略:
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="PresentationOptions"
如需詳細資訊,請參閱 mc:可忽略的屬性 頁面。
「解除凍結」是凍結的
一旦凍結,就永遠不能修改或解除凍結,不過,您可以使用 Clone 或 CloneCurrentValue 方法來建立未凍結的 Freezable 複製。
在下列範例中,會使用筆刷設定按鈕的背景,然後將筆刷凍結。 未凍結的複製會使用 Clone 方法來建立筆刷。 複製會被修改,並用來將按鈕的背景從黃色變更為紅色。
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 的。
Clone和 CloneCurrentValue 方法會產生無法凍結的深層複本。 如果可凍結的物件包含其他凍結的可凍結物件,則它們也會進行複製和修改。 例如,如果您複製凍結 PathGeometry 以使其成為可修改的,則它所包含的資料和區段也會複製並變成可修改。
建立您自己的凍結類別
衍生自 Freezable 的類別會取得下列功能。
特殊狀態:唯讀 (凍結) 和可寫入狀態。
執行緒安全:凍結 Freezable 可以跨執行緒共用。
詳細的變更通知:與其他 DependencyObject 的不同,可凍結的物件會在子屬性值變更時提供變更通知。
簡易複製:可凍結的類別已執行數個產生深層複製的方法。
Freezable是的型 DependencyObject 別,因此會使用相依性屬性系統。 您的 Freezable 類別屬性不必是相依性屬性,但使用相依性屬性將會減少您必須撰寫的程式碼數量,因為類別是以相依性屬性為考慮而設計的。 如需相依性屬性系統的詳細資訊,請參閱相依性 屬性總覽。
每個 Freezable 子類別都必須覆寫 CreateInstanceCore 方法。 如果您的類別使用其所有資料的相依性屬性,您就會完成。
如果您的類別包含非相依性屬性資料成員,您也必須覆寫下列方法:
您也必須觀察下列用來存取和寫入非相依性屬性之資料成員的規則:
在任何讀取非相依性屬性資料成員的 API 開頭,呼叫 ReadPreamble 方法。
在任何撰寫非相依性屬性資料成員的 API 開頭,呼叫 WritePreamble 方法。 (在 API 中呼叫 WritePreamble 之後,如果您也讀取非相依性屬性資料成員,就不需要另外進行呼叫 ReadPreamble 。 )
WritePostscript在結束寫入非相依性屬性資料成員的方法之前,請先呼叫方法。
如果您的類別包含屬於 DependencyObject 物件的非相依性屬性資料成員,則您也必須在每次變更其中一個值時呼叫 OnFreezablePropertyChanged 方法,即使您要將成員設定為 null
。
注意
使用基底執行的呼叫來開始您覆寫的每個 Freezable 方法,是很重要的。
如需自訂 Freezable 類別的範例,請參閱 自訂動畫範例。