一、資源(Resource)的定義
資源是儲存在可執行檔案中的一種不可執行資料。在WPF的資源中,幾乎可以包含圖像、字元串等所有的任意CLR對象,隻要對象有一個預設的構造函數和獨立的屬性。
也就是說,應用程式中非程式代碼的内容,比如點陣圖、顔色、字型、動畫/影片檔以及字元串常量值,可将它們從程式中獨立出來,單獨包裝成"資源(Resource)"。
資源的範圍(層級):
WPF提供一個封裝和存取資源(resource)的機制,我們可将資源建立在應用程式的不同範圍上。WPF中,資源定義的位置決定了該資源的可用範圍。資源可以定義在如下範圍中:
- 物件級:此時,資源隻能套用在這個Object物件,或套用至該物件的子物件。
- 檔案級:如果将資源定義在Window或Page層級的XAML檔中,那麼可以套用到這個檔案中的所有物件。
- 應用程式級:如果我們将資源定義在App.xaml 中,那麼,就可以将資源套用到應用程式内的任何地方。
- 字典級:當我們把資源封裝成一個資源字典, 定義到一個ResourceDictionary的XAML檔案時,就可以在另一個應用程式中重複使用。
每一個架構級元素( FrameworkElement 或者 FrameworkContentElement )都有一個資源屬性。每一個在資源字典中的資源都有一個唯一不重複的鍵值(key),在标簽中使用x:Key屬性來辨別它。
一般地,鍵值是一個字元串,但你也可以用合适的擴充标簽來設定為其他對象類型。非字元鍵值資源使用于特定的WPF區域,尤其是風格、元件資源,以及樣式資料等。
當資源被存儲進資源詞典後,我們可以通過兩種方式來使用這些資源一一靜态方式和動态方式。 Static指的是程式的非執行狀态而 Dynamic指的是程式運作狀态。對于資源的使用, Static 和 Dynamic也是這個意思。
靜态資源( StaticResource) 指的是在程式載入記憶體時對資源的一次性使用,之後就不再去通路這個資源了:
動态資源( DynamicResource) 指的是在程式運作過程中仍然會去通路資源。動态資源強制在每次通路此類資源時都重新進行查找。是以動态資源需要使用的系統開銷大于靜态資源的系統開銷。
如果你确定某些資源隻在程式初始化的時候使用一次、之後不會再改變,就應該使用StaticResource,而程式運作過程中還有可能改變的資源應該以 DynamicResource 形式使用。
二、示例
Title="test" Height="300" Width="300">
<Window.Resources>
<SolidColorBrush x:Key="ButtonBrush" Color="Red"/>
</Window.Resources>
<StackPanel>
<Button Margin="5" Content="Static Rescource A" Background="{StaticResource ButtonBrush}"/>
<Button Margin="5" Content="Static Rescource B" Background="{StaticResource ButtonBrush}">
<Button.Resources>
<SolidColorBrush x:Key="ButtonBrush" Color="Yellow"/>
</Button.Resources>
</Button>
<Button Margin="5" Content="Change Button Resource" Click="Button_Click_1"/>
<Button Margin="5" Content="Dynamic Rescource A" Background="{DynamicResource ButtonBrush}"/>
<Button Margin="5" Content="Dynamic Rescource B" x:Name="bt4" Background="{DynamicResource ButtonBrush}">
<Button.Resources>
<SolidColorBrush x:Key="ButtonBrush" Color="Yellow"/>
</Button.Resources>
</Button>
Button背景代碼:
private void Button_Click_1(object sender, RoutedEventArgs e)
{
SolidColorBrush brush = new SolidColorBrush(Colors.Green);
this.Resources["ButtonBrush"] = brush;
SolidColorBrush brush1 = new SolidColorBrush(Colors.Green);
this.bt4.Resources["ButtonBrush"] = brush1;
}
運作時的效果:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2YfNWawNyZuBnLyUTNzUzMwgTM4ETMxAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
點選Change Button Resource按鈕後的效果:
從程式執行的結果來看,我們可以得到如下的結論:
靜态資源引用是從控件所在的容器開始依次向上查找的,而動态資源的引用是從控件開始向上查找的(即控件的資源覆寫其父容器的同名資源)
更改資源時,動态引用的控件樣式發生變化(即"Dynamic Resource A"發生變化)
"Dynamic Resource B"發生變化是因為點選Change Button Resource按鈕後,通過x:Name關聯到Dynamic Resource B,直接改變了Dynamic Resource B的Resource。
StaticResource 查詢行為不支援向後引用,即不能引用在引用點之後才定義的資源。而DynamicResource可以向後引用,即DynamicResource運作時才查找并加載所定義的資源。
三、應用場景
靜态資源( StaticResource)應用場景:
- 應用程式設計幾乎将所有的應用程式資源集中到頁或應用程式級别的資源字典中。靜态資源引用不會基于運作時行為(例如重新加載頁)進行重新求值,是以,根據程式的資源和應用程式設計避免大量不必要的動态資源引用,這樣可以提高性能。
- 需要設定不在 DependencyObject 或 Freezable 上的的屬性的時候。
- 需要将資源編譯到dll中,并打包為程式的一部份,或者希望在各應用程式之間共享時。
- 需要為自定義控件建立一個主題(Theme),并定義在主題中使用的資源。對于這種情況,通常不用動态資源引用查找行為,而用靜态資源引用行為,以使該查找可預測并且獨立于該主題。使用動态資源引用時,即使是主題中的引用也會直到運作時才進行求值,并且在應用主題時,某個本地元素有可能會重新定義主題試圖引用的鍵,并且本地元素在查找中會位于主題本身之前。如果發生該情況,主題将不會按預期方式運作。
- 需要使用資源設定大量的依賴屬性(Dependency Property)的時候。依賴屬性具有屬性系統提供的值緩存機制,是以,如果能在程式裝載時設定依賴屬性的值,依賴屬性就不需要檢視重新求值的表達式,并且可以傳回最後一個有效值。該方法具有性能優勢。
- 需要為所有使用者更改基礎資源,或者需要通過使用 x:Shared 屬性為每個使用者維護獨立的可寫執行個體。
動态資源( DynamicResource)應用場景:
- 資源的值取決于直到運作時才知道的情況。這包括系統資源,或使用者可設定的資源。例如,由 SystemColors、SystemFonts 或 SystemParameters 公開的系統屬性的 setter 值。這些值是真正動态的,因為它們最終來自于使用者和作業系統的運作時環境。
- 為自定義控件建立或引用主題樣式(Theme Style)。
- 希望在應用程式運作期間調整資源字典( ResourceDictionary) 的内容。
- 有一個存在依存關系的複雜資源結構,在這種情況下,可能需要前向引用。靜态資源引用不支援前向引用,但動态資源引用支援,因為資源直到運作時才需要進行求值。
- 從編譯或工作集角度來說,所引用的資源特别大,并且加載頁時可能無法立即使用該資源。靜态資源引用始終在加載頁時從 XAML 加載;而動态資源引用直到實際使用時才會加載。
- 要建立的樣式(Style)的 setter 值可能來自受主題或其他使用者設定影響的值。
- 當引用資源的元素的父元素有可能在運作期改變,或可能會在邏輯樹中重新設定該元素的父級。父元素的改變将影響資源查詢的範圍。是以,如果希望基于新範圍對重新設定了父級元素的資源進行重新求值,請始終使用動态資源引用。
使用Dynamic Resource的限制條件:屬性必須是依賴屬性(Dependency Property),或是可當機(Freezable)的。
四、資源的查詢方式
**靜态資源( StaticResource)**的查詢
- 查找使用該資源的元素的Resource字典;
- 順着邏輯樹向上查找父元素的資源字典,直到根節點;
- 查找Application資源;
- 不支援向前引用,即:不能引用在引用點之後才定義的資源。
**動态資源( DynamicResource)**的查詢
- 查找使用該資源的元素的Resource字典;如果元素定義了一個Style 屬性,将查找Style中的資源字典;如果元素定義了一個Template屬性,将查找FrameworkTemplate中的資源字典。
- 順邏輯樹向上查找父元素的資源字典,直到根節點;
- 查找Application資源;
- 查找目前激活狀态下的Theme資源字典;
- 查找系統資源。