ResourceDictionary 與 XAML 資源參考

您可以使用 XAML 來定義應用程式的 UI 或資源。 資源通常是對您預期使用一次以上之某些物件的定義。 若要稍後參考 XAML 資源,您需要為資源指定一個索引鍵作為其名稱。 您可以參考整個應用程式或應用程式內的任何 XAML 頁面中的資源。 您可以使用來自 Windows 執行階段 XAML 的 ResourceDictionary 元素來定義資源。 然後,您可以使用 StaticResource 標記延伸ThemeResource 標記延伸來參考資源。

您可能最想要宣告為 XAML 資源的 XAML 元素包括 [樣式][ControlTemplate]、[動畫元件] 和 [筆刷] 子類別。 我們在此說明如何定義 ResourceDictionary 和索引鍵資源,以及 XAML 資源如何與您定義為應用程式或應用程式套件一部分的其他資源相關。 我們也說明資源字典進階功能,例如 MergedDictionariesThemeDictionaries

必要條件

對 XAML 標記的熟悉程度。 建議您閱讀 XAML 概觀

定義和使用 XAML 資源

XAML 資源是標記中多次被參考的物件。 資源在 ResourceDictionary 中定義,通常是在不同的檔案或標記頁面頂端,如下所示。

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Page.Resources>
        <x:String x:Key="greeting">Hello world</x:String>
        <x:String x:Key="goodbye">Goodbye world</x:String>
    </Page.Resources>

    <TextBlock Text="{StaticResource greeting}" Foreground="Gray" VerticalAlignment="Center"/>
</Page>

在此範例中:

  • <Page.Resources>…</Page.Resources> - 定義資源字典。
  • <x:String> - 以 "greeting" 索引鍵來定義資源。
  • {StaticResource greeting} - 查閱具有 "greeting" 索引鍵的資源;此索引鍵會指派給 TextBlockText 屬性。

注意請不要將與 ResourceDictionary 相關的概念,與在產生您應用程式套件之程式碼專案的構成內容中所討論的資源建置動作、資源 (.resw) 檔案或其他「資源」混淆。

資源不一定是字串;它們可以是任何可共用的物件,例如樣式、範本、筆刷和色彩。 不過,控制項、圖形和其他 FrameworkElement 無法共用,因此無法宣告為可重複使用的資源。 如需共用的詳細資訊,請參閱本主題後面的 XAML 資源必須可共用一節。

在這裡,筆刷和字串都會被宣告為資源,並由頁面中的控制項使用。

<Page
    x:Class="SpiderMSDN.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Page.Resources>
        <SolidColorBrush x:Key="myFavoriteColor" Color="green"/>
        <x:String x:Key="greeting">Hello world</x:String>
    </Page.Resources>

    <TextBlock Foreground="{StaticResource myFavoriteColor}" Text="{StaticResource greeting}" VerticalAlignment="Top"/>
    <Button Foreground="{StaticResource myFavoriteColor}" Content="{StaticResource greeting}" VerticalAlignment="Center"/>
</Page>

所有資源都需要有索引鍵。 索引鍵通常是使用 x:Key="myString"定義的字串。 不過,有一些其他方式可以指定索引鍵:

  • 樣式ControlTemplate需要 TargetType,且將會在未指定 x:Key 的情況下使用 TargetType 作為索引鍵。 在此情況下,索引鍵是實際的 [類型] 物件,而不是字串。 (請參閱底下的範例)
  • 具有 TargetTypeDataTemplate 資源將會在未指定 x:Key 的情況下使用 TargetType 作為索引鍵。 在此情況下,索引鍵是實際的 [類型] 物件,而不是字串。
  • 可以使用 x:Name 代替 x:Key。 不過,x:Name 也會為該資源產生程式碼後置欄位。 因此,x:Name 的效率比 x:Key 低,因為載入頁面時需要初始化該欄位。

StaticResource 標記延伸只能使用字串名稱 (x:Keyx:Name) 擷取資源。 不過,當 XAML 架構在決定尚未設定 樣式ContentTemplateItemTemplate 屬性的控制項所要使用的樣式與範本時,也會尋找隱含的樣式資源 (那些使用 TargetType 而不是 x:Key 或 x:Name 的資源)。

在這裡,Style \(英文\) 具有 typeof(Button) 的隱含索引鍵,而且由於頁面底部的 Button \(英文\) 未指定 Style \(英文\) 屬性,它會尋找索引鍵為 typeof(Button) 的樣式:

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Page.Resources>
        <Style TargetType="Button">
            <Setter Property="Background" Value="Red"/>
        </Style>
    </Page.Resources>
    <Grid>
       <!-- This button will have a red background. -->
       <Button Content="Button" Height="100" VerticalAlignment="Center" Width="100"/>
    </Grid>
</Page>

如需隱含樣式及其運作方式的詳細資訊,請參閱樣式設定控制項控制項範本

在程式碼中查閱資源

您可以像任何其他字典一樣存取資源字典的成員。

警告

當您在程式碼中執行資源查閱時,系統只會查看 Page.Resources 字典中的資源。 不同於 StaticResource 標記延伸,如果第一個字典中找不到資源,程式碼就不會回到 Application.Resources 字典。

 

此範例示範如何從頁面的資源字典中擷取 redButtonStyle 資源:

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Page.Resources>
        <Style TargetType="Button" x:Key="redButtonStyle">
            <Setter Property="Background" Value="red"/>
        </Style>
    </Page.Resources>
</Page>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            Style redButtonStyle = (Style)this.Resources["redButtonStyle"];
        }
    }
    MainPage::MainPage()
    {
        InitializeComponent();
        Windows::UI::Xaml::Style style = Resources().TryLookup(winrt::box_value(L"redButtonStyle")).as<Windows::UI::Xaml::Style>();
    }

若要從程式碼中查閱全應用程式資源,請使用 Application.Current.Resources 取得應用程式的資源字典,如下所示。

<Application
    x:Class="MSDNSample.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:SpiderMSDN">
    <Application.Resources>
        <Style TargetType="Button" x:Key="appButtonStyle">
            <Setter Property="Background" Value="red"/>
        </Style>
    </Application.Resources>

</Application>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            Style appButtonStyle = (Style)Application.Current.Resources["appButtonStyle"];
        }
    }
    MainPage::MainPage()
    {
        InitializeComponent();
        Windows::UI::Xaml::Style style = Application::Current().Resources()
                                                               .TryLookup(winrt::box_value(L"appButtonStyle"))
                                                               .as<Windows::UI::Xaml::Style>();
    }

您也可以在程式碼中新增應用程式資源。

這樣做時,請記住兩件事。

  • 首先,在任何頁面嘗試使用該資源之前,您需要新增這些資源。
  • 其次,您無法在應用程式的建構函式中新增資源。

如果您在 Application.OnLaunched 方法中新增資源,可以避免這兩個問題,如下所示。

// App.xaml.cs
    
sealed partial class App : Application
{
    protected override void OnLaunched(LaunchActivatedEventArgs e)
    {
        Frame rootFrame = Window.Current.Content as Frame;
        if (rootFrame == null)
        {
            SolidColorBrush brush = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 0, 255, 0)); // green
            this.Resources["brush"] = brush;
            // … Other code that VS generates for you …
        }
    }
}
// App.cpp

void App::OnLaunched(LaunchActivatedEventArgs const& e)
{
    Frame rootFrame{ nullptr };
    auto content = Window::Current().Content();
    if (content)
    {
        rootFrame = content.try_as<Frame>();
    }

    // Do not repeat app initialization when the Window already has content,
    // just ensure that the window is active
    if (rootFrame == nullptr)
    {
        Windows::UI::Xaml::Media::SolidColorBrush brush{ Windows::UI::ColorHelper::FromArgb(255, 0, 255, 0) };
        Resources().Insert(winrt::box_value(L"brush"), winrt::box_value(brush));
        // … Other code that VS generates for you …

每個 FrameworkElement 都可以有 ResourceDictionary

FrameworkElement 是控制項繼承的基類,並且具有 [資源] 屬性。 因此,您可以將本機資源字典新增至任何 FrameworkElement

在這裡,[頁面][框線] 都有資源字典,而且兩者都有稱為「問候語」的資源。 名為 'textBlock2' 的 TextBlock 位於框線 內,因此其資源查閱會先查閱 框線的資源,然後查閱頁面的資源,最後再查閱應用程式資源。 TextBlock 將讀取 "Hola mundo"。

若要從程式碼存取該元素的資源,請使用該元素的 [資源] 屬性。 存取程式碼中的 FrameworkElement 資源而不是 XAML,只會在該字典中而不是在父元素的字典中查閱。

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <x:String x:Key="greeting">Hello world</x:String>
    </Page.Resources>
    
    <StackPanel>
        <!-- Displays "Hello world" -->
        <TextBlock x:Name="textBlock1" Text="{StaticResource greeting}"/>

        <Border x:Name="border">
            <Border.Resources>
                <x:String x:Key="greeting">Hola mundo</x:String>
            </Border.Resources>
            <!-- Displays "Hola mundo" -->
            <TextBlock x:Name="textBlock2" Text="{StaticResource greeting}"/>
        </Border>

        <!-- Displays "Hola mundo", set in code. -->
        <TextBlock x:Name="textBlock3"/>
    </StackPanel>
</Page>

    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            textBlock3.Text = (string)border.Resources["greeting"];
        }
    }
    MainPage::MainPage()
    {
        InitializeComponent();
        textBlock3().Text(unbox_value<hstring>(border().Resources().TryLookup(winrt::box_value(L"greeting"))));
    }

合併的資源字典

合併的資源字典會將一個資源字典合併到另一個資源字典,通常是在另一個檔案中。

提示您可以使用 [專案] 功能表的 [新增]>[新增項目]>[資源字典] 選項,在 Microsoft Visual Studio 中建立資源字典檔案。

在這裡,您會在名為 Dictionary1.xaml 的個別 XAML 檔案中定義資源字典。

<!-- Dictionary1.xaml -->
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MSDNSample">

    <SolidColorBrush x:Key="brush" Color="Red"/>

</ResourceDictionary>

若要使用該字典,請將它與頁面的字典合併:

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Dictionary1.xaml"/>
            </ResourceDictionary.MergedDictionaries>

            <x:String x:Key="greeting">Hello world</x:String>

        </ResourceDictionary>
    </Page.Resources>

    <TextBlock Foreground="{StaticResource brush}" Text="{StaticResource greeting}" VerticalAlignment="Center"/>
</Page>

此範例中發生了以下情況。 您在<Page.Resources> 中,宣告 <ResourceDictionary>。 當您將資源新增至 <Page.Resources> 時,XAML 架構會隱含地為您建立資源字典;然而,在這種情況下,您不是只想要任何資源字典,而是一個包含合併字典的資源字典。

因此,您會宣告 <ResourceDictionary>,然後將項目新增至其 <ResourceDictionary.MergedDictionaries> 集合。 每一個項目都會採用 <ResourceDictionary Source="Dictionary1.xaml"/> 格式。 若要新增一個以上的字典,只要在第一個項目之後新增一個 <ResourceDictionary Source="Dictionary2.xaml"/> 項目。

<ResourceDictionary.MergedDictionaries>…</ResourceDictionary.MergedDictionaries>之後 ,您可以選擇性地將其他資源放在主字典中。 您使用來自合併字典的資源就像使用一般字典一樣。 在以上的範例中,{StaticResource brush} 會在子字典/合併字典中找到資源 (Dictionary1.xaml),而 {StaticResource greeting} 則會在主頁面字典中找到其資源。

在資源查閱序列中,只有在檢查該 ResourceDictionary 的其他所有索引資源之後,才會檢查 MergedDictionaries 字典。 搜尋該層級之後,就會查閱合併字典,並檢查 MergedDictionaries 中的每個項目。 如果有多個合併字典,這些字典會以在 [MergedDictionaries] 屬性中宣告的相反順序檢查。 在下列範例中,如果 Dictionary2.xaml 和 Dictionary1.xaml 都宣告了相同的索引鍵,則會先使用 Dictionary2.xaml 中的索引鍵,因為它是 MergedDictionaries 集合中的最後一個。

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Dictionary1.xaml"/>
                <ResourceDictionary Source="Dictionary2.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Page.Resources>

    <TextBlock Foreground="{StaticResource brush}" Text="greetings!" VerticalAlignment="Center"/>
</Page>

在任何一個 ResourceDictionary 的範圍內,檢查字典是否有索引鍵唯一性。 不過,該範圍不會延伸到不同 MergedDictionaries 檔案中的不同項目。

您可以結合使用查閱序列和跨合併字典範圍缺乏唯一鍵強制,來建立 ResourceDictionary 資源的後援值序列。 例如,您可以使用與應用程式的狀態和使用者喜好設定資料同步的資源字典,將特定筆刷色彩的使用者喜好設定資料,儲存在序列中最後合併的資源字典中。 不過,如果還沒有使用者喜好設定,您可以在初始 MergedDictionaries 檔案中,為 ResourceDictionary 資源定義相同的索引鍵字串,如此一來它就可以做為後援值。 請記住,您在主要資源字典中提供的任何值,都會在檢查合併字典之前進行檢查,因此如果您想要使用後援技術,請勿在主要資源字典中定義該資源。

主題資源和主題字典

ThemeResource 類似於 StaticResource,但主題變更時會重新評估資源查閱。

在此範例中,您會將 TextBlock 的前景設定為目前主題中的值。

<TextBlock Text="hello world" Foreground="{ThemeResource FocusVisualWhiteStrokeThemeBrush}" VerticalAlignment="Center"/>

主題字典是一種特殊類型的合併字典,它包含隨使用者目前在其裝置上使用的主題而變化的資源。 例如,[淺色] 主題可能會使用白色筆刷,而 [深色] 主題可能會使用深色筆刷。 筆刷會變更它所解析成的資源,但除此之外,使用筆刷做為資源的控制項組合仍可維持不變。 若要在您自己的範本和樣式中重新產生佈景主題切換行為,請使用 ThemeDictionaries 屬性取代將項目合併到主要字典時使用的 MergedDictionaries 屬性。

ThemeDictionaries 內的每個 ResourceDictionary 元素都必須有一個 x:Key 值。 該值是命名相關主題的字串,例如 “Default”、“Dark”、“Light” 或 “HighContrast”。 一般而言,Dictionary1Dictionary2 會定義具有相同名稱但不同值的資源。

在這裡,您使用紅色文字表示淺色主題,並使用藍色文字表示深色主題。

<!-- Dictionary1.xaml -->
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MSDNSample">

    <SolidColorBrush x:Key="brush" Color="Red"/>

</ResourceDictionary>

<!-- Dictionary2.xaml -->
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MSDNSample">

    <SolidColorBrush x:Key="brush" Color="blue"/>

</ResourceDictionary>

在此範例中,您會將 TextBlock 的前景設定為目前主題中的值。

<Page
    x:Class="MSDNSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <ResourceDictionary>
            <ResourceDictionary.ThemeDictionaries>
                <ResourceDictionary Source="Dictionary1.xaml" x:Key="Light"/>
                <ResourceDictionary Source="Dictionary2.xaml" x:Key="Dark"/>
            </ResourceDictionary.ThemeDictionaries>
        </ResourceDictionary>
    </Page.Resources>
    <TextBlock Foreground="{StaticResource brush}" Text="hello world" VerticalAlignment="Center"/>
</Page>

對於主題字典,每當使用 ThemeResource 標記延伸功能進行參考並且系統偵測到主題變更時,用於資源查閱的使用中字典就會動態變更。 系統完成的查閱行為是基於將使用中主題對應到特定主題字典的 x:Key

檢查主題字典在預設 XAML 設計資源中的建構方式非常有用,該資源與 Windows 執行階段預設為其控制項所使用的範本平行。 使用文字編輯器或 IDE 在 \(Program Files)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<SDK version>\Generic 中開啟 XAML 檔案。 請注意如何在 generic.xaml 中先定義主題字典,以及每個主題字典如何定義相同的索引鍵。 然後,每個這樣的鍵都由主題字典外部的各種鍵控元素中的組合元素參考,並稍後在 XAML 中定義。 還有一個單獨的 themeresources.xaml 檔案用於設計,其中僅包含主題資源和額外範本,而不包含預設控制項範本。 主題區域與您在 generic.xaml 中看到的內容重複。

當您使用 XAML 設計工具編輯樣式和範本的複本時,設計工具會從 XAML 設計資源字典中擷取區段,並將它們放置為屬於應用程式和專案的 XAML 字典元素的本機複本。

如需詳細資訊,以及您的應用程式可以使用的主題特定和系統資源清單,請參閱 XAML 主題資源

XAML 資源參考的查閱行為

查閱行為 是描述 XAML 資源系統如何嘗試尋找 XAML 資源的詞彙。 當從應用程式的 XAML 中的某個位置將某個鍵作為 XAML 資源參考進行引用時,就會發生查閱。 首先,資源系統具有可預測的行為,可以根據範圍檢查資源是否存在。 如果在初始範圍內未找到資源,則範圍會擴大。 查閱行為在 XAML 資源可能由應用程式或系統定義的位置和範圍內持續進行。 如果所有可能的資源查閱嘗試都失敗,通常會導致錯誤。 這些錯誤通常可以在開發過程中消除。

XAML 資源參考的查閱行為會以套用實際使用方式的物件及其本身的 [資源] 屬性開始。 如果 ResourceDictionary \(英文\) 存在,系統會檢查該 ResourceDictionary 是否有項目含有所要求的索引鍵。 此第一層查閱很少相關,因為您通常不會定義然後參考相同物件上的資源。 事實上,此處通常不存在 [資源] 屬性。 您可以從 XAML 中的幾乎任何位置進行 XAML 資源參考;您不僅限於 FrameworkElement 子類別的屬性。

然後,查閱序列檢查應用程式的執行階段物件樹狀結構中的下一個上層物件。 如果 FrameworkElement.Resources 存在並保存 ResourceDictionary,則會要求具有指定索引鍵字串的字典項目。 如果找到資源,則查閱順序會停止,並將物件提供給參考的位置。 否則,查閱行為會往下一個父層級前進到物件樹狀根。 搜尋繼續遞歸向上,直到到達 XAML 的根元素,從而耗盡所有可能的直接資源位置的搜尋。

注意

在頁面的根層級定義所有直接資源是常見的做法,既可以利用這種資源查閱行為,也可以作為 XAML 標記樣式的慣例。

如果在立即資源中找不到要求的資源,下一個查閱步驟是檢查 [Application.Resources] 屬性。 Application.Resources 是放置應用程式導覽結構中多個頁面所參考之任何應用程式特定資源的最佳位置。

重要

資源新增至 ResourceDictionary 的順序會影響其套用順序。 XamlControlsResources 字典會覆寫許多預設的資源索引鍵,因此應先將其新增至 Application.Resources,以免其覆寫您應用程式中的任何其他自訂樣式或資源。

控制項範本在參考查閱中還有另一個可能的位置:主題字典。 主題字典是具有 ResourceDictionary 元素做為其根目錄的單一 XAML 檔案。 主題字典可能是 Application.Resources 中的合併字典。 主題字典也可能是範本化自訂控制項的控制項特定主題字典。

最後,針對平台資源進行資源查閱。 平台資源包括為每個系統 UI 主題定義的控制項範本,以及定義 Windows 執行階段應用程式中用於 UI 的所有控制項的預設外觀。 平台資源還包括一組與系統範圍的外觀和主題相關的具名資源。 就技術而言,這些資源是 MergedDictionaries 項目,因此在應用程式載入後即可從 XAML 或程式碼中找到。 例如,系統主題資源包括名為「SystemColorWindowTextColor」的資源,該資源提供色彩定義,以將應用程式文字色彩與來自作業系統和使用者喜好設定的系統視窗文字色彩相符。 應用程式的其他 XAML 樣式可以參考此樣式,或者您的程式碼可以取得資源查閱值 (並在範例案例中轉換為色彩)。

如需使用 XAML 的 Windows 應用程式可用的佈景主題專用資源和系統資源詳細資訊和清單,請參閱 XAML 佈景主題資源

如果在上述任何位置中仍然找不到要求的索引鍵,就會發生 XAML 剖析錯誤/例外狀況。 在某些情況下,XAML 剖析例外狀況,可能是未透過 XAML 標記編譯動作或 XAML 設計環境偵測到的執行階段例外狀況。

由於資源字典的分層查閱行為,您可以刻意定義多個資源項目,只要每個資源都在不同的層級上定義,每個資源項目都具有與索引鍵相同的字串值。 換句話說,雖然索引鍵在任何指定的 ResourceDictionary 內都必須是唯一的,但唯一性需求不會延伸到整個查閱行為序列。 在查閱期間,只有成功擷取的第一個這類物件會用於 XAML 資源參考,然後查閱就會停止。 您可以使用此行為在應用程式的 XAML 中的不同位置索引鍵請求相同的 XAML 資源,但會返回不同的資源,這取決於 XAML 資源參考的範圍以及特定查閱的行為管道。

在 ResourceDictionary 內向前參考

特定資源字典中的 XAML 資源參考必須參考已使用索引鍵定義的資源,且該資源在詞法上必須出現在資源參考之前。 XAML 資源參考無法解析向前參考。 基於這個理由,如果您使用來自另一個資源內的 XAML 資源參考,則必須設計資源字典結構,讓其他資源所使用的資源先定義在資源字典中。

在應用程式層級定義的資源無法參考直接資源。 這相當於嘗試向前參考,因為應用程式資源實際上是首先處理的 (當應用程式首次啟動時,在加載任何瀏覽頁面內容之前)。 不過,任何直接資源都可以參考應用程式資源,這是避免向前參考情況的實用技術。

XAML 資源必須可共用

物件若要存在於 ResourceDictionary \(英文\) 中,就必須「可被共用」

需要共用,因為當應用程式的物件樹狀結構在執行階段建構及使用時,物件不能存在於樹狀結構中的多個位置。 在內部,資源系統會在要求每個 XAML 資源時,建立資源值複本,以在應用程式的物件圖形中使用。

ResourceDictionary 和 Windows 執行階段 XAML 通常支援這些物件以供共用使用:

如果您遵循必要的實作模式,也可以使用自訂類型作為可共用的資源。 您可以在支援程式碼中定義這類類別 (或在包含的執行階段元件中),然後將這些類別具現化為資源。 範例包括資料繫結的物件資料來源和 IValueConverter 實作。

自訂類型必須有預設建構函式,因為這是 XAML 剖析器用來具現化類別的建構函式。 當成資源使用的自訂類型在其繼承中不能有 UIElement \(英文\) 類別,因為 UIElement 永遠不能共用 (其一向是用來代表存在於您執行階段應用程式的物件圖形中單一位置的單一 UI 元素)。

UserControl 使用範圍

UserControl 元素對於資源查閱行為有特殊情況,因為它具有定義範圍和使用範圍固有的概念。 從其定義範圍建立 XAML 資源參考的 UserControl,必須能夠支援在其自己的定義範圍查閱序列內查閱該資源,即它無法存取應用程式資源。 從 UserControl 使用範圍中,資源參考會被視為位於其使用頁面根目錄的查閱序列中(就像從載入的物件樹狀結構中的物件所建立的任何其他資源參考一樣),而且可以存取應用程式資源。

ResourceDictionary 和 XamlReader.Load

您可以使用 ResourceDictionary 作為 XamlReader.Load 方法的根或 XAML 輸入的一部分。 如果所有此類參考在提交載入的 XAML 中完全獨立,則也可以在該 XAML 中包含 XAML 資源參考。 XamlReader.Load 會在不知道任何其他 ResourceDictionary 物件 (甚至是 Application.Resources \(英文\)) 的內容中剖析 XAML。 此外,請勿在提交至 XamlReader.Load 的 XAML 內使用 {ThemeResource}

從程序碼使用 ResourceDictionary

ResourceDictionary 的大部分案例,是在 XAML 中專門處理的。 您可以將 ResourceDictionary 容器和資源宣告為 UI 定義檔案中的 XAML 檔案或 XAML 節點集。 然後使用 XAML 資源參考,向 XAML 的其他部分要求這些資源。 不過,在某些案例中,您的應用程式可能會想要使用在應用程式執行時執行的程式碼來調整 ResourceDictionary 的內容,或至少查詢 ResourceDictionary 的內容,以查看是否已定義資源。 這些程式碼呼叫是在 ResourceDictionary 執行個體上所進行,所以您必須先擷取一個,無論是透過取得 FrameworkElement.Resources 來再物件樹狀中某處的立即 ResourceDictionary,或是 Application.Current.Resources

在 C# 或 Microsoft Visual Basic 程式碼中,您可以使用索引子 (項目) 來參考指定 ResourceDictionary 中的資源。 ResourceDictionary 是字串索引鍵字典,因此索引器會使用字串索引鍵,而不是整數索引。 在 Visual C++ 元件延伸 (C++/CX) 程式碼中,請使用 [查閱]

使用程式碼來檢查或變更 ResourceDictionary 時,查閱項目等 API 的行為,不會從直接資源周遊到應用程式資源;這是 XAML 剖析器行為,只會在載入 XAML 頁面時發生。 在執行階段,索引鍵的範圍獨立於您當時使用的 ResourceDictionary 執行個體。 不過,該範圍會延伸到 MergedDictionaries

此外,如果您要求的索引鍵不存在於 ResourceDictionary \(英文\),系統可能不會出現錯誤;傳回值可能只會提供為 null。 不過,如果您嘗試使用傳回的 null 做為值,您仍可能會收到錯誤訊息。 錯誤會來自屬性的 setter,而不是您的 ResourceDictionary 呼叫。 唯一避免錯誤的方式是,如果屬性接受 null 做為有效值, 請注意此行為與 XAML 剖析時間的 XAML 查閱行為形成對比的方式;在剖析時無法從 XAML 解析提供的索引鍵會導致 XAML 剖析錯誤,即使在屬性可能已接受 null 的情況下也是如此。

合併的資源字典會包含在主要資源字典的索引範圍中,以在執行階段參考合併的字典。 換句話說,您可以使用主要字典的 ItemLookup \(英文\) 來尋找實際在合併字典中定義的任何物件。 在此情況下,查閱行為與剖析時間 XAML 查閱行為類似:如果合併的字典中有多個物件,且每個物件都有相同的索引鍵,則會傳回上一個新增字典中的物件。

您可以透過呼叫 新增 (C# 或 Visual Basic) 或 插入 (C++/CX),將項目新增到現有的 ResourceDictionary。 您可以將項目新增至直接資源或應用程式資源。 這兩個 API 呼叫都需要索引鍵,這符合 ResourceDictionary 中每個項目都必須有索引鍵的需求。 不過,您在執行階段新增至 ResourceDictionary 的項目與 XAML 資源參考無關。 當 XAML 第一次剖析為載入應用程式 (或偵測到主題變更) 時,就會發生 XAML 資源參考的必要查閱。 在執行階段新增至集合的資源無法使用,而改變 ResourceDictionary 並不會使已擷取的資源失效,即使您變更該資源的值也一樣。

您也可以在執行階段從 ResourceDictionary 移除項目、製作部分或所有項目的複本,或執行其他作業。 ResourceDictionary 的成員清單會指出有哪些 API 可供使用。 請注意,因為 ResourceDictionary 具有預計的 API 來支援它的基礎集合介面,您的 API 選項會根據您是使用 C#、Visual Basic 或是 C++/CX 而有所差異。

ResourceDictionary 和當地語系化

XAML ResourceDictionary 一開始可能包含要當地語系化的字串。 如果是,請將這些字串儲存為專案資源,而不是儲存在 ResourceDictionary。 從 XAML 中取出字串,改為給所屬元素一個 x:Uid directive 值。 然後,在資源檔案中定義資源。 以 XUIDValue 格式提供資源名稱。PropertyName 和應當地語系化之字串的資源值。

自訂資源查閱

針對進階案例,您可以實作一個具有與本主題中所述的 XAML 資源參考查閱行為不同之行為的類別。 若要這樣做,您需要實作 CustomXamlResourceLoader \(英文\) 類別,然後就可以使用 CustomResource 標記延伸 \(部分機器翻譯\) (而不是使用 StaticResourceThemeResource) 進行資源參考,以存取該行為。 大多數應用程式不會有需要這樣做的案例。 如需詳細資訊,請參閱 CustomXamlResourceLoader.