Freezable 物件概觀
本主題描述如何有效地使用和建立 Freezable 物件,其提供特殊功能來協助改善應用程式效能。 可凍結物件的範例包括筆刷、畫筆、轉換、幾何和動畫。
什麼是冰凍?
Freezable是具有兩種狀態的特殊物件類型:解除凍結和凍結。 解除凍結時, Freezable 似乎就像任何其他物件一樣。 凍結時, Freezable 無法再修改 。
Freezable提供 Changed 事件,以通知觀察者對 物件所做的任何修改。 凍結 Freezable 可以改善其效能,因為它不再需要將資源花在變更通知上。 凍結 Freezable 也可以跨執行緒共用,但無法凍結 Freezable 。
雖然 類別 Freezable 有許多應用程式,但 Windows Presentation Foundation (WPF) 中的大部分 Freezable 物件都與圖形子系統相關。
類別 Freezable 可讓您更輕鬆地使用特定圖形系統物件,並可協助改善應用程式效能。 繼承自 Freezable 的類型範例包括 Brush 、 Transform 和 Geometry 類別。 因為它們包含 Unmanaged 資源,所以系統必須監視這些物件以進行修改,然後在原始物件有變更時更新其對應的 Unmanaged 資源。 即使您實際上未修改圖形系統物件,系統仍必須花費部分資源來監視物件,以防您變更它。
例如,假設您建立 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 圖形子系統會使用您提供的資訊來繪製圖元群組,以建立按鈕的外觀。 雖然您使用純色筆刷來描述按鈕的繪製方式,但純色筆刷實際上不會進行繪製。 圖形系統會為按鈕和筆刷產生快速、低階的物件,而它是實際出現在畫面上的物件。
如果您要修改筆刷,則必須重新產生這些低階物件。 freezable 類別可讓筆刷能夠尋找其對應的產生的低階物件,並在變更時加以更新。 啟用此功能時,筆刷據說是「解除凍結」。
freezable 的 Freeze 方法可讓您停用此自我更新功能。 您可以使用此方法讓筆刷變成「凍結」或不可修改。
注意
並非所有 Freezable 物件都可以凍結。 若要避免擲回 InvalidOperationException ,請檢查 Freezable 物件的 CanFreeze 屬性值,以判斷是否可以在嘗試凍結之前凍結它。
if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}
If myBrush.CanFreeze Then
' Makes the brush unmodifiable.
myBrush.Freeze()
End If
當您不再需要修改可凍結時,凍結可提供效能優勢。 如果您在此範例中凍結筆刷,圖形系統就不再需要監視它是否有變更。 圖形系統也可以進行其他優化,因為它知道筆刷不會變更。
注意
為了方便起見,除非您明確凍結可凍結物件,否則可凍結的物件會維持未凍結狀態。
使用 Freezables
使用未凍結的凍結就像使用任何其他類型的物件一樣。 在下列範例中,在用來繪製按鈕背景之後,的色彩 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 ,它所包含的圖形和區段也會凍結。
如果下列任一項成立,則無法凍結 Freezable :
如果這些條件為 false,而且您不打算修改 Freezable ,則您應該凍結它以取得稍早所述的效能優點。
一旦您呼叫 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:Ignorable 屬性 將屬性標示 PresentationOptions:Freeze
為可忽略:
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="PresentationOptions"
如需詳細資訊,請參閱 mc:Ignorable Attribute 頁面。
「Unfreezing」 a Freezable
凍結之後, Freezable 永遠無法修改或解除凍結;不過,您可以使用 或 CloneCurrentValue 方法建立未凍結的複製 Clone 品。
在下列範例中,按鈕的背景是以筆刷設定,然後凍結該筆刷。 未凍結的複本是使用 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 方法會產生可凍結的深層複本。 如果 freezable 包含其他凍結的可凍結物件,它們也會複製並加以修改。 例如,如果您複製凍結 PathGeometry 使其可修改,也會複製它所包含的圖形和區段,並加以修改。
建立您自己的 Freezable 類別
衍生自 Freezable 的類別會取得下列功能。
特殊狀態:唯讀(凍結)和可寫入狀態。
執行緒安全性:凍結 Freezable 可以線上程之間共用。
詳細變更通知:不同于其他 DependencyObject ,Freezable 物件會在子屬性值變更時提供變更通知。
容易複製:Freezable 類別已實作數個產生深層複製的方法。
Freezable是 的 DependencyObject 型別,因此會使用相依性屬性系統。 您的類別屬性不必是相依性屬性,但使用相依性屬性會減少您必須撰寫的程式碼數量,因為 Freezable 類別是以相依性屬性設計。 如需相依性屬性系統的詳細資訊,請參閱 相依性屬性概觀 。
每個 Freezable 子類別都必須覆寫 CreateInstanceCore 方法。 如果您的類別針對所有資料使用相依性屬性,則表示您已完成。
如果您的類別包含非相依性屬性資料成員,您也必須覆寫下列方法:
您也必須遵守下列規則,以存取和寫入非相依性屬性的資料成員:
在任何讀取非相依性屬性資料成員的 API 開頭,呼叫 ReadPreamble 方法。
在寫入非相依性屬性資料成員的任何 API 開頭,呼叫 WritePreamble 方法。 (一旦您在 API 中呼叫 WritePreamble ,如果您也讀取非相依性屬性資料成員,就不需要對 進行額外的呼叫 ReadPreamble 。
WritePostscript在結束寫入至非相依性屬性資料成員的方法之前,先呼叫 方法。
如果您的類別包含屬於 DependencyObject 物件的非相依性屬性資料成員,即使您將成員設定為 null
,您也必須在每次變更其中一個值時呼叫 OnFreezablePropertyChanged 方法。
注意
請務必使用對基底實作的呼叫來開始覆寫的每個 Freezable 方法。
如需自訂 Freezable 類別的範例,請參閱 自訂動畫範例 。
另請參閱
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應