WPF性能优化:Freezable 对象
Freezable是WPF中一個特殊的基類,用于創(chuàng)建可以凍結(jié)(Freeze)的可變對象。凍結(jié)一個對象意味著將其狀態(tài)設(shè)置為只讀,從而提高性能并允許在多線程環(huán)境中共享對象。
Freezable的應(yīng)用
我們定義畫刷資源的時候常常會這樣寫:
<SolidColorBrush x:Key="RedBrush" Color="Red" o:Freeze="True"/>
代碼中的o:Freeze="True"其實就是使用Freezable的 Freeze方法凍結(jié)畫刷,使之不可修改,系統(tǒng)不必監(jiān)視該畫刷對象,從而減少資源消耗。
o:Freeze="True"乍一看像附加屬性,其實并不是的。Freeze屬性是http://schemas.microsoft.com/winfx/2006/xaml/presentation/optionsXML命名空間中定義的唯一屬性或其他編程元素。Freeze屬性專門存在于此特殊命名空間中,以便在根元素聲明中可以使用。處理Freeze屬性的功能專門內(nèi)置于處理已編譯應(yīng)用程序的 XAML的XAML處理器中。
那是不是WPF中的所有資源都可以(需要)使用Freeze方法凍結(jié)來提高性能呢?
Freezable類通常用于WPF中的資源和動畫,例如創(chuàng)建可重用的畫刷、幾何圖形和動畫。從Freezable繼承的類型包括Brush、Transform和Geometry類。由于它們包含非托管資源,因此系統(tǒng)必須監(jiān)視這些對象發(fā)生的修改,然后在原始對象發(fā)生更改時更新對應(yīng)的非托管資源。即使實際上并未修改圖形系統(tǒng)對象,系統(tǒng)仍必須消耗一些資源來監(jiān)視該對象,以防更改它。
例如,假設(shè)創(chuàng)建一個SolidColorBrush畫筆并用它來繪制按鈕的背景。
<Window.Resources>
<SolidColorBrush x:Key="RedBrush" Color="Red"/>
</Window.Resources>
<Button Background="{StaticResource RedBrush}"/>
呈現(xiàn)按鈕時,WPF圖形子系統(tǒng)使用你提供的信息來繪制一組像素,以創(chuàng)建按鈕的外觀。盡管使用純色畫筆來描述按鈕的繪制方式,但純色畫筆實際上并沒有進(jìn)行繪制。圖形系統(tǒng)為按鈕和畫筆生成快速、低級別的對象,實際顯示在屏幕上的就是這些對象。
如果要修改畫筆,則必須重新生成這些低級別對象。Freezable類使畫筆能夠找到生成的相應(yīng)低級別對象并在更改時更新它們。
注意事項
并非每個Freezable對象都可以凍結(jié)。為避免引發(fā)InvalidOperationException,請在嘗試凍結(jié)Freezable對象之前檢查該對象的CanFreeze屬性值,以確定是否可以將其凍結(jié)。如果滿足以下任一條件,則無法凍結(jié)Freezable:
- 它具有動畫屬性或數(shù)據(jù)綁定屬性。
- 它具有由動態(tài)資源設(shè)置的屬性。
- 它包含無法凍結(jié)的Freezable子對象。
Freezable對象調(diào)用Freeze方法凍結(jié)后,就無法解凍。修改凍結(jié)對象屬性時會引發(fā)InvalidOperationException。但是,可以使用Clone或CloneCurrentValue方法創(chuàng)建(深拷貝)解凍的副本。如果Freezable包含其他已凍結(jié)的 Freezable對象,它們也會被克隆并變?yōu)榭尚薷摹?/p>
無論使用哪種克隆方法,動畫都不會復(fù)制到新的 Freezable。
由于無法對凍結(jié)的Freezable進(jìn)行動畫處理,因此使用Storyboard對其進(jìn)行動畫處理時,動畫系統(tǒng)會自動創(chuàng)建凍結(jié)的Freezable對象的可修改克隆。為了消除克隆導(dǎo)致的性能開銷,如果需要對對象進(jìn)行動畫處理,請讓其保持解凍狀態(tài)。
附加屬性實現(xiàn)XAML中Freeze
上文中提到o:Freeze="True"并不是通過附加屬性實現(xiàn),而是內(nèi)置于XAML處理器中實現(xiàn)。我們自己也可以通過附加屬性的方式實現(xiàn),代碼如下:
public class PresentationOptionsAttach
{
public static bool GetFreeze(Freezable freezable)
{
return (bool)freezable.GetValue(FreezeProperty);
}
public static void SetFreeze(Freezable freezable, bool value)
{
freezable.SetValue(FreezeProperty, value);
}
public static readonly DependencyProperty FreezeProperty =
DependencyProperty.RegisterAttached("Freeze", typeof(bool), typeof(PresentationOptionsAttach), new PropertyMetadata(false, OnFreezeChanged));
private static void OnFreezeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (DesignerProperties.GetIsInDesignMode(d)) return;
if ((bool)e.NewValue)
{
Freezable freezable = d as Freezable;
if (freezable.CanFreeze)
freezable.Freeze();
}
}
}
小結(jié)
Freezable是一個我們既熟悉又陌生的類,熟悉是因為我們經(jīng)常使用,陌生是因為很少關(guān)注其優(yōu)化性能的機(jī)制以及需要注意的地方。本文簡單介紹了Freezable優(yōu)化性能的機(jī)制以及注意事項,并提供了通過附加屬性的方式在XAML中凍結(jié)資源。
總結(jié)
以上是生活随笔為你收集整理的WPF性能优化:Freezable 对象的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQL Server中获取不同格式的日期
- 下一篇: 2023-08-06:小青蛙住在一条河边