XAML 資源概觀 (WPF .NET)

資源是可在應用程式中不同位置重複使用的物件。 資源的範例包括筆刷和樣式。 此概觀描述如何使用可延伸應用程式標記語言 (XAML) 中的資源。 您也可以使用程式碼來建立和存取資源。

注意

本文所述的 XAML 資源與應用程式資源 不同 ,這些資源通常是新增至應用程式的檔案,例如內容、資料或內嵌檔案。

重要

.NET 7 和 .NET 6 的桌面指南檔正在建置中。

在 XAML 中使用資源

下列範例會將 SolidColorBrush 定義為頁面上根項目上的 資源。 然後,此範例會參考資源,並用它來設定數個 EllipseTextBlock 子專案的屬性,包括 、 和 Button

<Window x:Class="resources.ResExample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ResExample" Height="400" Width="300">
    <Window.Resources>
        <SolidColorBrush x:Key="MyBrush" Color="#05E0E9"/>
        <Style TargetType="Border">
            <Setter Property="Background" Value="#4E1A3D" />
            <Setter Property="BorderThickness" Value="5" />
            <Setter Property="BorderBrush">
                <Setter.Value>
                    <LinearGradientBrush>
                        <GradientStop Offset="0.0" Color="#4E1A3D"/>
                        <GradientStop Offset="1.0" Color="Salmon"/>
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
        </Style>
        <Style TargetType="TextBlock" x:Key="TitleText">
            <Setter Property="FontSize" Value="18"/>
            <Setter Property="Foreground" Value="#4E87D4"/>
            <Setter Property="FontFamily" Value="Trebuchet MS"/>
            <Setter Property="Margin" Value="0,10,10,10"/>
        </Style>
        <Style TargetType="TextBlock" x:Key="Label">
            <Setter Property="HorizontalAlignment" Value="Right"/>
            <Setter Property="FontSize" Value="13"/>
            <Setter Property="Foreground" Value="{StaticResource MyBrush}"/>
            <Setter Property="FontFamily" Value="Arial"/>
            <Setter Property="FontWeight" Value="Bold"/>
            <Setter Property="Margin" Value="0,3,10,0"/>
        </Style>
    </Window.Resources>

    <Border>
        <StackPanel>
            <TextBlock Style="{StaticResource TitleText}">Title</TextBlock>
            <TextBlock Style="{StaticResource Label}">Label</TextBlock>
            <TextBlock HorizontalAlignment="Right" FontSize="36" Foreground="{StaticResource MyBrush}" Text="Text" Margin="20" />
            <Button HorizontalAlignment="Left" Height="30" Background="{StaticResource MyBrush}" Margin="40">Button</Button>
            <Ellipse HorizontalAlignment="Center" Width="100" Height="100" Fill="{StaticResource MyBrush}" Margin="10" />
        </StackPanel>
    </Border>

</Window>

每個架構層級專案 ( FrameworkElement 或) 都有 Resources 屬性,這是 ResourceDictionary 包含已定義 FrameworkContentElement 資源的型別。 您可以在任何專案上定義資源,例如 Button 。 不過,資源最常定義在根項目上,也就是 Window 範例中的資源。

資源字典中的每個資源都必須有唯一索引鍵。 當您在標記中定義資源時,您可以透過 x:Key 指示詞指派唯一索引鍵。 索引鍵通常是字串;不過,您也可以使用適當的標記延伸,將它設定為其他物件類型。 WPF 中某些功能區域會使用非字串索引鍵,特別是樣式、元件資源和資料樣式。

您可以使用已定義的資源搭配資源標記延伸語法,以指定資源的索引鍵名稱。 例如,使用資源作為另一個專案上的屬性值。

<Button Background="{StaticResource MyBrush}"/>
<Ellipse Fill="{StaticResource MyBrush}"/>

在上述範例中,當 XAML 載入器處理 上 Button 屬性的值 {StaticResource MyBrush}Background 時,資源查閱邏輯會先檢查元素的資源字典 Button 。 如果 Button 沒有資源索引鍵 MyBrush 的定義(在該範例中沒有;其資源集合是空的),則查閱會接著檢查 的 Button 父元素。 如果未在父代上定義資源,它會繼續向上檢查物件的邏輯樹狀結構,直到找到為止。

如果您在根項目上定義資源,邏輯樹狀結構中的所有專案,例如 WindowPage ,都可以存取它。 而且,您可以重複使用相同的資源來設定接受資源所代表之相同類型之任何屬性的值。 在上一個範例中,相同的 MyBrush 資源會設定兩個不同的屬性: Button.Background Ellipse.Fill

靜態和動態資源

資源可以參考為靜態或動態。 參考是使用 StaticResource 標記延伸 DynamicResource 標記延伸 來建立。 標記延伸是一項 XAML 功能,可讓您指定物件參考,方法是讓標記延伸處理屬性字串,並將物件傳回 XAML 載入器。 如需標記延伸行為的詳細資訊,請參閱標記延伸和 WPF XAML

當您使用標記延伸時,通常會以字串形式提供一或多個參數,這些參數是由該特定標記延伸所處理。 StaticResource 標記延伸會藉由在所有可用的資源字典中尋找該索引鍵的值來處理索引鍵。 載入期間會發生處理,也就是載入程式需要指派屬性值時。 DynamicResource 標記延伸 會藉由建立運算式來處理索引鍵,而且該運算式會維持未評估,直到應用程式執行為止,此時會評估運算式以提供值。

當您參考資源時,下列考量可能會影響您使用靜態資源參考或動態資源參考:

  • 當您決定如何為應用程式建立資源的整體設計時,請考慮下列事項:每個頁面、在應用程式中、在鬆散的 XAML 或僅限資源元件中:

  • 應用程式的功能。 是否在應用程式需求中即時更新資源?

  • 該資源參考型別的相關查閱行為。

  • 特定屬性或資源類型,以及這些類型的原生行為。

靜態資源

靜態資源參考最適用於下列情況:

  • 您的應用程式設計會將大部分的資源集中到頁面或應用層級資源字典中。

    靜態資源參考不會根據執行時間行為重新評估,例如重載頁面。 因此,當您的資源和應用程式設計不需要動態資源參考時,可能會有一些效能優點,以避免大量動態資源參考。

  • 您正在設定不在 或 Freezable 上的 DependencyObject 屬性值。

  • 您正在建立資源字典,該字典會編譯成應用程式之間共用的 DLL。

  • 您要為自訂控制項建立主題,並定義主題內所使用的資源。

    在此情況下,您通常不希望動態資源參考查閱行為。 請改用靜態資源參考行為,讓查閱可預測且獨立到主題。 使用動態資源參考時,即使是主題內的參考,在執行時間之前仍會保持未評估。 而且,在套用主題時,某些本機元素會重新定義主題嘗試參考的索引鍵,而本機元素將會落在查閱主題本身之前。 如果發生這種情況,您的主題將不會如預期般運作。

  • 您使用資源來設定大量的相依性屬性。 相依性屬性具有屬性系統所啟用的有效值快取,因此,如果您為可在載入時評估的相依性屬性提供值,則相依性屬性不需要檢查重新評估的運算式,而且可以傳回最後一個有效值。 這項技術可能會提升效能。

  • 您想要變更所有消費者的基礎資源,或想要使用 x:Shared 屬性為每個消費者維護不同的可寫入執行個體。

靜態資源查閱行為

下列描述屬性或專案參考靜態資源時自動發生的查閱程式:

  1. 查閱程序會檢查設定屬性之項目所定義的資源字典內,是否有要求的索引鍵。

  2. 查閱程式接著會將邏輯樹狀結構向上周遊至父元素及其資源字典。 此程式會繼續進行,直到到達根項目為止。

  3. 已檢查應用程式資源。 應用程式資源是 WPF 應用程式物件所 Application 定義之資源字典內的那些資源。

資源字典內的靜態資源參考必須參考資源參考之前已在語彙上定義的資源。 靜態資源參考無法解析向前參考。 基於這個理由,請設計您的資源字典結構,讓資源定義于每個個別資源字典的開頭或附近。

靜態資源查閱可以延伸至主題或系統資源,但僅支援此查閱,因為 XAML 載入器會延遲要求。 延遲是必要的,因此頁面載入時執行時間主題會正確套用至應用程式。 不過,不建議將已知只存在於主題或系統資源的索引鍵的靜態資源參考,因為如果使用者即時變更主題,就不會重新評估這類參考。 當您要求佈景主題或系統資源時,動態資源參考會更可靠。 但佈景主題項目本身要求另一個資源時則例外。 這些參考應該是靜態資源參考,原因如前所述。

如果找不到靜態資源參考,則例外狀況行為會有所不同。 如果已延遲資源,則會在執行階段發生例外狀況。 如果資源未延遲,則例外狀況會在載入時發生。

動態資源

動態資源在下列情況下最能運作:

  • 資源的值,包括系統資源,或其他使用者可設定的資源,取決於執行時間之前未知的條件。 例如,您可以建立 setter 值,將系統屬性參考為 、 SystemColorsSystemFonts 、 或 SystemParameters 所公開。 由於這些值最終是來自使用者和作業系統的執行階段環境,因此是真正動態的。 您也可能有會變更的應用程式層級佈景主題,其中的頁面層級資源存取也必須擷取該變更。

  • 您正在建立或參考自訂控制項的主題樣式。

  • 您想要在應用程式存留期內調整 的內容 ResourceDictionary

  • 您有內含相互依存性的複雜資源結構,可能需要向前參考。 靜態資源參考不支援正向參考,但動態資源參考確實支援它們,因為資源在執行時間之前不需要評估,因此轉送參考不是相關的概念。

  • 您參考的是從編譯或工作集的觀點來看的大型資源,而且頁面載入時可能不會立即使用資源。 頁面載入時,靜態資源參考一律會從 XAML 載入。 不過,動態資源參考在使用之前不會載入。

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

  • 您要將資源套用至在應用程式存留期間邏輯樹狀結構中可能重新父項的專案。 變更父代也可能會變更資源查閱範圍,因此如果您想要根據新範圍重新評估重設父代項目的資源,請一律使用動態資源參考。

動態資源查閱行為

如果您呼叫 FindResourceSetResourceReference ,動態資源參考的資源查閱行為會平行處理常式代碼中的查閱行為:

  1. 查閱會檢查設定 屬性之專案所定義之資源字典內要求的索引鍵:

  2. 查閱會將邏輯樹狀結構向上周遊至父元素及其資源字典。 此程式會繼續進行,直到到達根項目為止。

  3. 已檢查應用程式資源。 應用程式資源是 WPF 應用程式物件所 Application 定義之資源字典內的那些資源。

  4. 已檢查目前使用中主題的主題資源字典。 如果佈景主題在執行階段變更,則會重新評估其值。

  5. 檢查系統資源。

例外狀況行為 (如果有的話) 則有所不同:

  • 如果呼叫要求 FindResource 資源且找不到,則會擲回例外狀況。

  • 如果呼叫要求 TryFindResource 資源且找不到,則不會擲回例外狀況,且傳回的值為 null 。 如果所設定的屬性不接受 null ,則根據所設定的個別屬性,仍可能會擲回更深層的例外狀況。

  • 如果資源是由 XAML 中的動態資源參考要求且找不到,則行為取決於一般屬性系統。 一般行為就像資源所在的層級上沒有發生任何屬性設定作業一樣。 例如,如果您嘗試使用無法評估的資源,在個別按鈕元素上設定背景,則不會設定任何值的結果,但有效值仍可能來自屬性系統和值優先順序中的其他參與者。 例如,背景值可能仍來自本機定義的按鈕樣式或主題樣式。 對於主題樣式未定義的屬性,失敗的資源評估後的有效值可能來自屬性中繼資料中的預設值。

限制

動態資源參考有一些值得注意的限制。 至少下列其中一個條件必須成立:

由於所設定的屬性必須是 DependencyPropertyFreezable 屬性,因此大部分的屬性變更都可以傳播至 UI,因為屬性系統會認可屬性變更(已變更的動態資源值)。 大部分的控制項都包含邏輯,如果 DependencyProperty 變更且該屬性可能會影響版面配置,則會強制控制項的另一個配置。 不過,並非所有屬性都有 DynamicResource 標記延伸 做為其值,保證會在 UI 中提供即時更新。 該功能可能仍會根據 屬性而有所不同,以及視擁有屬性的類型,或甚至是您應用程式的邏輯結構而定。

樣式、DataTemplates 和隱含索引鍵

雖然 中的所有 ResourceDictionary 專案都必須有索引鍵,但這並不表示所有資源都必須有明確的 x:Key 。 有幾種物件類型會在定義為資源時支援隱含索引鍵,其中索引鍵值會繫結至另一個屬性的值。 這種類型的金鑰稱為隱含索引鍵,而 x:Key 屬性是明確的索引鍵。 您可以藉由指定明確索引鍵,來覆寫任何隱含索引鍵。

資源的其中一個重要 Style 案例是當您定義 時。 事實上, Style 幾乎一律定義為資源字典中的專案,因為樣式原本就打算重複使用。 如需樣式的詳細資訊,請參閱 樣式和範本 (WPF .NET)

控制項的樣式可以透過隱含索引鍵來建立及參考。 定義預設控制項外觀的佈景主題樣式會依賴此隱含索引鍵。 從要求它的觀點來看,隱含索引鍵是 Type 控制項本身的 。 從定義資源的觀點來看,隱含索引鍵是 TargetType 樣式的 。 因此,如果您要為自訂控制項建立主題,或建立與現有主題樣式互動的樣式,則不需要 指定該 Style 的 x:Key 指示詞 。 如果您想要使用主題樣式,則完全不需要指定任何樣式。 例如,即使資源似乎沒有索引鍵, Style 下列樣式定義仍可運作:

<Style TargetType="Button">
    <Setter Property="Background" Value="#4E1A3D" />
    <Setter Property="Foreground" Value="White" />
    <Setter Property="BorderThickness" Value="5" />
    <Setter Property="BorderBrush">
        <Setter.Value>
            <LinearGradientBrush>
                <GradientStop Offset="0.0" Color="#4E1A3D"/>
                <GradientStop Offset="1.0" Color="Salmon"/>
            </LinearGradientBrush>
        </Setter.Value>
    </Setter>
</Style>

該樣式確實有一個索引鍵:隱含索引鍵:類型 System.Windows.Controls.Button 。 在標記中,您可以直接指定 TargetType 作為類型名稱(或者您可以選擇性地使用 {x:Type...} 傳回 Type

透過 WPF 所使用的預設主題樣式機制,該樣式會套用為頁面上 的 Button 執行時間樣式,即使 Button 本身不會嘗試指定其 Style 屬性或樣式的特定資源參考。 在頁面中定義的樣式比主題字典樣式早于查閱序列中找到,其索引鍵與主題字典樣式具有相同的索引鍵。 您可以只指定 <Button>Hello</Button> 頁面中的任何位置,而您定義的 TargetTypeButton 樣式會套用至該按鈕。 如果您想要的話,您仍然可以明確地將樣式與標記中的類型值 TargetType 相同,但這是選擇性的。

如果 OverridesDefaultStyletrue ,則樣式的隱含索引鍵不適用於 控制項。 (另請注意, OverridesDefaultStyle 可能會設定為控制項類別的原生行為一部分,而不是明確設定在 控制項的實例上。此外,為了支援衍生類別案例的隱含索引鍵,控制項必須覆寫 DefaultStyleKey (WPF 隨附的所有現有控制項都包含此覆寫)。 如需樣式、佈景主題和控制項設計的詳細資訊,請參閱設計可設定樣式控制項的方針

DataTemplate 也有隱含索引鍵。 的 DataTemplate 隱含索引鍵是 DataType 屬性值。 DataType 也可以指定為類型的名稱,而不是明確地使用 {x:Type...} 。 如需詳細資訊,請參閱資料範本化概觀

另請參閱