1. 程式人生 > 實用技巧 >StaticResource標記擴充套件和DynamicResource標記擴充套件的使用區別

StaticResource標記擴充套件和DynamicResource標記擴充套件的使用區別

靜態和動態資源

資源可引用為靜態資源或動態資源。可通過使用StaticResource 標記擴充套件DynamicResource 標記擴充套件建立引用。標記擴充套件是 XAML 的一項功能,可以通過使用標記擴充套件來處理屬性字串並將物件返回到 XAML 載入程式,從而指定物件引用。有關標記擴充套件行為的詳細資訊,請參閱標記擴充套件和 WPF XAML

使用標記擴充套件時,通常會以字串的形式提供一個或多個由該特定標記擴充套件處理的引數。StaticResource 標記擴充套件通過在所有可用的資源字典中查詢鍵值來處理鍵。處理在載入期間進行,即載入過程需要分配屬性值時。DynamicResource 標記擴充套件

則通過建立表示式來處理鍵,而且表示式會保持未計算狀態,直至應用執行為止。當應用實際執行時,表示式會進行計算並提供一個值。

在引用某個資源時,下列注意事項可能會對於使用靜態資源引用還是使用動態資源引用產生影響:

  • 確定如何為應用建立資源的整體設計(在每頁上、在應用程式中、在寬鬆的 XAML 中或在僅包含資源的程式集中)時,請考慮以下事項:

  • 應用的功能。實時更新資源是否為應用要求的一部分?

  • 該資源引用型別的相應查詢行為。

  • 特定的屬性或資源型別,以及這些型別的本機行為。

靜態資源

在以下情況下,最適合使用靜態資源引用:

  • 應用設計將其大多數資源集中到頁面或應用程式級資源字典中。靜態資源引用不基於執行時行為(例如過載頁面)重新計算。因此,根據資源和應用設計,如果避免不必要地使用大量動態資源引用,可能會一定程度地提高效能。

  • 要設定不在DependencyObjectFreezable上的屬性的值。

  • 要建立的資源字典將編譯成 DLL,並將打包為應用的一部分或在應用間共享。

  • 要為自定義控制元件建立主題,並要定義在主題中使用的資源。在這種情況下,通常不希望執行動態資源引用查詢行為,而是希望執行靜態資源引用行為,以確保查詢可預測並自包含到主題中。使用動態資源引用時,即使主題中的引用也會在執行時前保持未計算狀態。而且,主題可能會得到應用,但某個本地元素仍會重新定義主題正嘗試引用的鍵,並且該本地元素在查詢期間會排在主題之前。如果發生這種情況,主題的行為將偏離預期方式。

  • 要使用資源設定大量依賴屬性。依賴屬性會通過屬性系統啟用有效值快取功能;因此,如果為可在載入時進行計算的依賴屬性提供了值,則該依賴屬性不必檢查是否存在重新計算的表示式並可返回最後一個有效值。此項技術可以提高效能。

  • 想為所有使用者更改基礎資源,或想通過使用x:Shared 屬性為每個使用者維護單獨的可寫例項。

靜態資源查詢行為

下面介紹屬性或元素引用靜態資源時自動發生的查詢過程:

  1. 查詢程序在用於設定屬性的元素所定義的資源字典中查詢請求的鍵。

  2. 查詢過程隨後會向上遍歷邏輯樹,以查詢父元素及其資源字典。此過程到達根元素後才會停止。

  3. 檢查應用資源。應用資源就是Application物件為 WPF 應用定義的資源字典中的資源。

從資源字典中進行的靜態資源引用必須引用已在資源引用前進行過詞法定義的資源。靜態資源引用無法解析前向引用。因此,請設計資源字典的結構,以便在每個相應資源字典的開頭或鄰近開頭的位置定義資源。

靜態資源查詢可以擴充套件到主題或系統資源中,但此查詢受支援只是因為 XAML 載入程式推遲了請求。為了讓頁面載入時的執行時主題正確地應用到應用,這種延遲是必需的。但是,不建議使用對已知僅在主題中存在或作為系統資源存在的鍵的靜態資源引用,因為如果使用者實時更改主題,不會重新計算此類引用。請求主題或系統資源時,動態資源引用更為可靠。例外情況是當主題元素自身請求另一個資源。出於上述原因,這些引用應該是靜態資源引用。

因找不到靜態資源引用而引發的異常行為各不相同。如果資源被延遲,則異常會在執行時發生。如果資源未延遲,則異常會在載入時發生。

動態資源

在以下情況下,最適合使用動態資源:

  • 資源(包括系統資源或使用者可設定的資源)的值取決於直到執行時才知道的條件。例如,你可以建立 setter 值(引用由SystemColorsSystemFontsSystemParameters公開的系統屬性)。這些值是真正的動態值,因為它們最終來自使用者和作業系統的執行時環境。或許還擁有可能會發生變化的應用程式級主題,而頁面級資源訪問也必須捕獲其中的變化。

  • 要為自定義控制元件建立或引用主題樣式。

  • 打算在應用生存期內調整ResourceDictionary的內容。

  • 擁有存在相互依賴關係且可能需要進行前向引用的複雜資源結構。靜態資源引用不支援前向引用,但動態資源引用支援,因為資源在執行時之前不需要計算,所以前向引用是一個不相關的概念。

  • 要引用從編譯或工作集的角度來看很大的資源,而且該資源在頁面載入時可能不會立即使用。頁面載入時,始終會從 XAML 載入靜態資源引用。但是,動態資源引用在使用前不會載入。

  • 要建立的樣式的 setter 值可能來自受主題或其他使用者設定影響的其他值。

  • 要將資源應用於可能會在應用生存期內在邏輯樹中重定父級的元素。父級更改後,資源查詢範圍也可能會隨之更改;因此,如果希望重定父級的元素的資源基於新範圍重新進行計算,請始終使用動態資源引用。

動態資源查詢行為

如果呼叫FindResourceSetResourceReference,則動態資源引用的資源查詢行為會與程式碼中的查詢行為並行執行:

  1. 查詢在用於設定屬性的元素所定義的資源字典中查詢請求的鍵:

  2. 查詢會向上遍歷邏輯樹,以查詢父元素及其資源字典。此過程到達根元素後才會停止。

  3. 檢查應用資源。應用資源就是Application物件為 WPF 應用定義的資源字典中的資源。

  4. 檢查主題資源字典中當前處於活動狀態的主題。如果主題在執行時發生更改,則會重新計算值。

  5. 檢查系統資源。

異常行為(如果有)各不相同:

  • 如果FindResource呼叫請求了某個資源但未找到該資源,則會引發異常。

  • 如果TryFindResource呼叫請求了某個資源但未找到該資源,不會引發任何異常,並且返回的值為null如果要設定的屬性不接受null,則仍有可能引發更深的異常(取決於要設定的單獨屬性)。

  • 如果 XAML 中的動態資源引用請求了某個資源但未找到該資源,則行為取決於常規屬性系統。常規行為即存在資源的級別上沒有發生屬性設定操作時執行的行為。例如,如果嘗試使用無法計算的資源來設定個別按鈕元素上的背景,則值設定操作不會產生任何結果,但有效值可能仍來自屬性系統和值優先順序中的其他參與者。例如,背景值可能仍來自在本地定義的某個按鈕樣式,或來自主題樣式。對於並非由主題樣式定義的屬性,資源計算失敗後的有效值可能來自屬性元資料中的預設值。

限制

動態資源引用存在一些重要限制。必須至少滿足以下條件之一:

由於要設定的屬性必須是DependencyPropertyFreezable屬性,大多數屬性更改都可以傳播到 UI,這是因為屬性更改(更改的動態資源值)會經由屬性系統確認。大多數控制元件都包含相應的邏輯;當DependencyProperty有所更改且該屬性可能會影響佈局時,該邏輯將強制使用控制元件的其他佈局。但是,並不保證所有使用DynamicResource 標記擴充套件作為其值的屬性都能在 UI 中提供實時更新。此功能可能仍會因屬性、屬性所屬的型別,甚至應用的邏輯結構而異。