ResourceDictionary 和 XAML 资源引用ResourceDictionary and XAML resource references

你可以使用 XAML 为你的应用定义 UI 或资源。You can define the UI or resources for your app using XAML. 资源通常是一些你预期多次使用的对象的定义。Resources are typically definitions of some object that you expect to use more than once. 为了在以后引用 XAML 资源,你为资源指定一个键,用于充当其名称。To refer to a XAML resource later, you specify a key for a resource that acts like its name. 你可以在整个应用中或从应用中的任意 XAML 页面引用资源。You can reference a resource throughout an app or from any XAML page within it. 你可以使用 Windows 运行时 XAML 中的 ResourceDictionary 元素定义你的资源。You can define your resources using a ResourceDictionary element from the Windows Runtime XAML. 然后,可使用 StaticResource 标记扩展ThemeResource 标记扩展来引用你的资源。Then, you can reference your resources by using a StaticResource markup extension or ThemeResource markup extension.

你最希望声明为 XAML 资源的 XAML 元素包括 StyleControlTemplate、动画组件和 Brush 子类。The XAML elements you might want to declare most often as XAML resources include Style, ControlTemplate, animation components, and Brush subclasses. 我们在此处介绍如何定义 ResourceDictionary 和键控资源,以及 XAML 资源与你定义为应用或应用包一部分的其他资源有何关系。Here, we explain how to define a ResourceDictionary and keyed resources, and how XAML resources relate to other resources that you define as part of your app or app package. 我们还介绍资源字典高级功能,如 MergedDictionariesThemeDictionariesWe also explain resource dictionary advanced features such as MergedDictionaries and ThemeDictionaries.

先决条件Prerequisites

我们假设你了解 XAML 标记并已阅读 XAML 概述We assume that you understand XAML markup and have read the XAML overview.

定义和使用 XAML 资源Define and use XAML resources

XAML 资源是多次从标记中引用的对象。XAML resources are objects that are referenced from markup more than once. 资源在 ResourceDictionary 中定义,通常位于单独的文件中或位于标记页面的顶部,如下所示。Resources are defined in a ResourceDictionary, typically in a separate file or at the top of the markup page, like this.

<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>

在本示例中:In this example:

  • <Page.Resources>…</Page.Resources> - 定义资源字典。- Defines the resource dictionary.
  • <x:String> - 定义带有键“greeting”的资源。- Defines the resource with the key "greeting".
  • {StaticResource greeting} - 查找带有键“greeting”的资源,它已分配给 TextBlockText 属性。- Looks up the resource with the key "greeting", which is assigned to the Text property of the TextBlock.

注意   ResourceDictionary 相关的概念与“资源生成操作、资源 (.resw) 文件或在构建生成应用包的代码项目上下文中讨论的其他“资源”相混淆。Note  Don't confuse the concepts related to ResourceDictionary with the Resource build action, resource (.resw) files, or other "resources" that are discussed in the context of structuring the code project that produces your app package.

资源不需要作为字符串;它们可以作为任何可共享的对象,例如样式、目标、画笔和颜色。Resources don't have to be strings; they can be any shareable object, such as styles, templates, brushes, and colors. 但是,控件、形状和其他 FrameworkElement 不可共享,因此不能将其声明为可重复使用的资源。However, controls, shapes, and other FrameworkElements are not shareable, so they can't be declared as reusable resources. 有关共享的详细信息,请参阅本主题后面的 XAML 资源必须可共享部分。For more info about sharing, see the XAML resources must be shareable section later in this topic.

在此处,画笔和字符串都声明为资源,并由页面中的控件使用。Here, both a brush and a string are declared as resources and used by controls in a page.

<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>

所有资源都需要有一个键。All resources need to have a key. 通常,键是通过 x:Key=”myString” 定义的字符串。Usually that key is a string defined with x:Key=”myString”. 但是,还有几种其他方法可指定键:However, there are a few other ways to specify a key:

  • 如果未指定 x:Key,则 StyleControlTemplate 需要 TargetType,并且将 TargetType 用作键。Style and ControlTemplate require a TargetType, and will use the TargetType as the key if x:Key is not specified. 在这种情况下,键是实际的 Type 对象,而非字符串。In this case, the key is the actual Type object, not a string. (请参阅下方示例)(See examples below)
  • 如果未指定 x:Key,具有 TargetTypeDataTemplate 资源会将 TargetType 用作键。DataTemplate resources that have a TargetType will use the TargetType as the key if x:Key is not specified. 在这种情况下,键是实际的 Type 对象,而非字符串。In this case, the key is the actual Type object, not a string.
  • x:Name 可以代替 x:Key 使用。x:Name can be used instead of x:Key. 但是,x:Name 还会为资源生成代码隐藏字段。However, x:Name also generates a code behind field for the resource. 因此,x:Name 的效率低于 x:Key,因为该字段需要在页面加载时进行初始化。As a result, x:Name is less efficient than x:Key because that field needs to be initialized when the page is loaded.

StaticResource 标记扩展可以仅使用字符串名称(x:Keyx:Name)检索资源。The StaticResource markup extension can retrieve resources only with a string name (x:Key or x:Name). 但是,XAML 框架在决定为尚未设置 StyleContentTemplateItemTemplate 属性的控件使用哪个样式和模板时,还将查找隐式样式资源(使用 TargetType 而非 x:Key 或 x:Name 的资源)。However, the XAML framework also looks for implicit style resources (those which use TargetType rather than x:Key or x:Name) when it decides which style & template to use for a control that hasn't set the Style and ContentTemplate or ItemTemplate properties.

此处的 Style 具有隐式键 typeof(Button),并且由于页面底部的 Button 未指定 Style 属性,它将查找具有 typeof(Button) 键的样式:Here, the Style has an implicit key of typeof(Button), and since the Button at the bottom of the page doesn't specify a Style property, it looks for a style with key of 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> 
       <!-- This button will have a red background. -->
       <Button Content="Button" Height="100" VerticalAlignment="Center" Width="100"/>
</Page>

有关隐式样式及其工作方式的详细信息,请参阅设置控件样式控件模板For more info about implicit styles and how they work, see Styling controls and Control templates.

查找代码中的资源Look up resources in code

像任何其他字典一样,访问资源字典的成员。You access members of the resource dictionary like any other dictionary.

注意  当你执行在代码中查找资源的操作时,仅找到 Page.Resources 字典中的资源。Caution  When you perform a resource lookup in code, only the resources in the Page.Resources dictionary are looked at. StaticResource 标记扩展不同,如果未在第一个字典中找到这些资源,该代码不会回退到 Application.Resources 字典。Unlike the StaticResource markup extension, the code doesn't fall back to the Application.Resources dictionary if the resources aren’t found in the first dictionary.

此示例演示如何在页面的资源字典中检索出 redButtonStyle 资源。This example shows how to retrieve the redButtonStyle resource out of a page’s resource dictionary:

<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"];
        }
    }

若要在代码中查找应用范围的资源,请使用 Application.Current.Resources 获取应用的资源目录,如下所示。To look up app-wide resources from code, use Application.Current.Resources to get the app's resource dictionary, as shown here.

<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"];
        }
    }

你还可以在代码中添加应用程序资源。You can also add an application resource in code.

以下是在执行此操作时要记住的两个事项:There are two things to keep in mind when doing this.

  • 第一,在任何页面尝试使用资源时,你需要先添加资源。First, you need to add the resources before any page tries to use the resource.
  • 第二,不能在应用的构造函数中添加资源。Second, you can’t add resources in the App’s constructor.

如果在 Application.OnLaunched 方法中添加资源,可以避免这两个问题,如下所示。You can avoid both problems if you add the resource in the Application.OnLaunched method, like this.

// 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 …
        }
    }
}

每个 FrameworkElement 都可以具有 ResourceDictionaryEvery FrameworkElement can have a ResourceDictionary

FrameworkElement 是控件所继承的基类,并且具有 Resources 属性。FrameworkElement is a base class that controls inherit from, and it has a Resources property. 因此你可以将本地资源字典添加到任何 FrameworkElementSo, you can add a local resource dictionary to any FrameworkElement.

此时,资源字典已添加到页面元素。Here, a resource dictionary is added to a page element.

<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>

    <Border>
        <Border.Resources>
            <x:String x:Key="greeting">Hola mundo</x:String>
        </Border.Resources>
        <TextBlock Text="{StaticResource greeting}" Foreground="Gray" VerticalAlignment="Center"/>
    </Border>
</Page>

此时,PageBorder 都具有资源字典,并且都具有名为“greeting”的资源。Here, both the Page and the Border have resource dictionaries, and they both have a resource called "greeting". TextBlock 位于 Border 内,因此其资源查找将依次查找 Border 的资源、Page 的资源以及 Application 资源。The TextBlock is inside the Border, so its resource lookup looks first to the Border’s resources, then the Page’s resources, and then the Application resources. TextBlock 将读取“Hola mundo”。The TextBlock will read "Hola mundo".

若要从代码访问元素的资源,请使用该元素的 Resources 属性。To access that element’s resources from code, use that element’s Resources property. 在代码(而非 XAML)中访问 FrameworkElement 的资源,将仅在该字典中查找,而不在父级元素的字典中查找。Accessing a FrameworkElement’s resources in code, rather than XAML, will look only in that dictionary, not in parent element’s dictionaries.

<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>

    <Border x:Name="border">
        <Border.Resources>
            <x:String x:Key="greeting">Hola mundo</x:String>
        </Border.Resources>
    </Border>
</Page>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            string str = (string)border.Resources["greeting"];
        }
    }

合并的资源字典Merged resource dictionaries

合并的资源字典将一个资源字典合并到通常在其他文件中的另一个字典。A merged resource dictionary combines one resource dictionary into another, usually in another file.

提示  可以在 Microsoft Visual Studio 中创建资源字典文件,方法是在项目菜单中依次使用添加 > 新建项目…> 资源字典选项。Tip  You can create a resource dictionary file in Microsoft Visual Studio by using the Add > New Item… > Resource Dictionary option from the Project menu.

此时,可以在名为 Dictionary1.xaml 的单独 XAML 文件中定义资源字典。Here, you define a resource dictionary in a separate XAML file called Dictionary1.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>

若要使用该字典,请将它与页面的字典合并:To use that dictionary, you merge it with your page’s dictionary:

<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>

下面是本示例中会出现的结果。Here's what happens in this example. <Page.Resources> 中,声明 <ResourceDictionary>In <Page.Resources>, you declare <ResourceDictionary>. 当你向 <Page.Resources> 添加资源时,XAML 框架将为你隐式创建资源字典;但是在这种情况下,你需要的不仅是任一资源字典,你还需要包含合并字典的资源字典。The XAML framework implicitly creates a resource dictionary for you when you add resources to <Page.Resources>; however, in this case, you don’t want just any resource dictionary, you want one that contains merged dictionaries.

因此请声明 <ResourceDictionary>,然后将内容添加到其 <ResourceDictionary.MergedDictionaries> 集合。So you declare <ResourceDictionary>, then add things to its <ResourceDictionary.MergedDictionaries> collection. 其中每个条目都采用 <ResourceDictionary Source="Dictionary1.xaml"/> 形式。Each of those entries takes the form <ResourceDictionary Source="Dictionary1.xaml"/>. 若要添加多个字典,只需在第一个条目后添加 <ResourceDictionary Source="Dictionary2.xaml"/> 条目即可。To add more than one dictionary, just add a <ResourceDictionary Source="Dictionary2.xaml"/> entry after the first entry.

<ResourceDictionary.MergedDictionaries>…</ResourceDictionary.MergedDictionaries> 后,你可以选择在主字典中放置其他资源。After <ResourceDictionary.MergedDictionaries>…</ResourceDictionary.MergedDictionaries>, you can optionally put additional resources in your main dictionary. 你可以使用要合并到的字典中的资源,如同使用常规字典一样。You use resources from a merged to dictionary just like a regular dictionary. 在上述示例中,{StaticResource brush} 在子级/合并字典 (Dictionary1.xaml) 中查找资源,而 {StaticResource greeting} 在主页字典中查找其资源。In the example above, {StaticResource brush} finds the resource in the child/merged dictionary (Dictionary1.xaml), while {StaticResource greeting} finds its resource in the main page dictionary.

在资源查找序列中,仅在检查 ResourceDictionary 的所有其他键控资源后,才会检查 MergedDictionaries 字典。In the resource-lookup sequence, a MergedDictionaries dictionary is checked only after a check of all the other keyed resources of that ResourceDictionary. 搜索该级别后,查找会深入到合并后的字典,且对 MergedDictionaries 中的每一项进行检查。After searching that level, the lookup reaches the merged dictionaries, and each item in MergedDictionaries is checked. 如果存在多个合并的字典,会按在 MergedDictionaries 属性中声明这些字典的顺序的相反顺序来检查它们。If multiple merged dictionaries exist, these dictionaries are checked in the inverse of the order in which they are declared in the MergedDictionaries property. 在以下示例中,如果 Dictionary2.xaml 和 Dictionary1.xaml 声明同一个键,则首先使用来自 Dictionary2.xaml 中的键,因为它排在 MergedDictionaries 集的末尾。In the following example, if both Dictionary2.xaml and Dictionary1.xaml declared the same key, the key from Dictionary2.xaml is used first because it's last in the MergedDictionaries set.

<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 范围内,均会检查字典中键的唯一性。Within the scope of any one ResourceDictionary, the dictionary is checked for key uniqueness. 但是,这一范围不会扩展到不同 MergedDictionaries 文件中的不同项。However, that scope does not extend across different items in different MergedDictionaries files.

可以结合使用查找序列和跨合并字典范围不强制使用唯一键来创建 ResourceDictionary 资源的回退值序列。You can use the combination of the lookup sequence and lack of unique key enforcement across merged-dictionary scopes to create a fallback value sequence of ResourceDictionary resources. 例如,你可能会使用与应用的状态数据和用户首选项数据同步的资源词典,为序列中最后合并的资源字典中的特殊画笔颜色存储用户首选项。For example, you might store user preferences for a particular brush color in the last merged resource dictionary in the sequence, using a resource dictionary that synchronizes to your app's state and user preference data. 但是,如果尚不存在任何用户首选项,则可为初始 MergedDictionaries 文件中的 ResourceDictionary 资源定义相同的键字符串,并可将其用作回退值。However, if no user preferences exist yet, you can define that same key string for a ResourceDictionary resource in the initial MergedDictionaries file, and it can serve as the fallback value. 请记住,始终会在检查合并字典之前检查你在主要资源字典中提供的任何值,所以如果希望使用回退技术,则不要在主要资源字典中定义该资源。Remember that any value you provide in a primary resource dictionary is always checked before the merged dictionaries are checked, so if you want to use the fallback technique, don't define that resource in a primary resource dictionary.

主题资源和主题字典Theme resources and theme dictionaries

ThemeResource 类似于 StaticResource,但资源查找会在主题更改时进行重新评估。A ThemeResource is similar to a StaticResource, but the resource lookup is reevaluated when the theme changes.

在此示例中,将 TextBlock 的前景设置为当前主题中的值。In this example, you set the foreground of a TextBlock to a value from the current theme.

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

主题字典是一种特殊类型的合并字典,用于保存各种资源,具体资源取决于用户当前在其设备上使用的主题。A theme dictionary is a special type of merged dictionary that holds the resources that vary with the theme a user is currently using on his or her device. 例如,“浅色”主题可能使用白色画笔,而“深色”主题可能使用黑色画笔。For example, the "light" theme might use a white color brush whereas the "dark" theme might use a dark color brush. 画笔会更改它所溶入的资源,但使用该画笔作为资源的控件的组成可能保持不变。The brush changes the resource that it resolves to, but otherwise the composition of a control that uses the brush as a resource could be the same. 若要在个人模板或样式中重现主题切换行为而不将 MergedDictionaries 用作属性以将项目合并到主词典中,请使用 ThemeDictionaries 属性。To reproduce the theme-switching behavior in your own templates and styles, instead of using MergedDictionaries as the property to merge items into the main dictionaries, use the ThemeDictionaries property.

ThemeDictionaries 内的每个 ResourceDictionary 元素必须具有一个 x:Key 值。Each ResourceDictionary element within ThemeDictionaries must have an x:Key value. 该值是一个字符串,它为相关主题命名,例如 “Default”、“Dark”、“Light”或“HighContrast”。The value is a string that names the relevant theme—for example, "Default", "Dark", "Light", or "HighContrast". 通常,Dictionary1Dictionary2 将定义名称相同但值不同的资源。Typically, Dictionary1 and Dictionary2 will define resources that have the same names but different values.

在此处,将红色文本用于浅色主题,蓝色文本用于深色主题。Here, you use red text for the light theme and blue text for the dark theme.

<!-- 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 的前景设置为当前主题中的值。In this example, you set the foreground of a TextBlock to a value from the current theme.

<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 标记扩展进行引用并且系统检测到主题更改时,要用于资源查找的活动字典都会动态更改。For theme dictionaries, the active dictionary to be used for resource lookup changes dynamically, whenever ThemeResource markup extension is used to make the reference and the system detects a theme change. 系统执行的查找行为基于将活动主题映射到特定主题字典的 x:Key 操作。The lookup behavior that is done by the system is based on mapping the active theme to the x:Key of a specific theme dictionary.

检查主题字典在默认 XAML 设计资源中的构建方式十分有用,这些资源与 Windows 运行时默认用作其控件的模板相对应。It can be useful to examine the way that the theme dictionaries are structured in the default XAML design resources, which parallel the templates that the Windows Runtime uses by default for its controls. 使用文本编辑器或 IDE 打开 \(Program Files)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<SDK version>\Generic 中的 XAML 文件。Open the XAML files in \(Program Files)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<SDK version>\Generic using a text editor or your IDE. 请注意主题字典首先在 generic.xaml 中的定义方式,以及每个主题字典定义相同键的方式。Note how the theme dictionaries are defined first in generic.xaml, and how each theme dictionary defines the same keys. 然后每个这样的键由构成各种键控元素的元素所引用,这些键控元素位于主题字典外部并且稍后在 XAML 中定义。Each such key is then referenced by elements of composition in the various keyed elements that are outside the theme dictionaries and defined later in the XAML. 还存在用于设计的单独 themeresources.xaml 文件,该文件仅包含主题资源和额外模板,不包含默认控件模板。There's also a separate themeresources.xaml file for design that contains only the theme resources and extra templates, not the default control templates. 这些主题区域是你将在 generic.xaml 中看到的内容副本。The theme areas are duplicates of what you'd see in generic.xaml.

当你使用 XAML 设计工具以编辑样式和模板的副本时,设计工具会提取 XAML 设计资源词典中的片段并将其作为应用和项目一部分的 XAML 字典元素的本地副本放置。When you use XAML design tools to edit copies of styles and templates, the design tools extract sections from the XAML design resource dictionaries and place them as local copies of XAML dictionary elements that are part of your app and project.

有关可用于应用的特定于主题的资源和系统资源的详细信息和列表,请参阅 XAML 主题资源For more info and for a list of the theme-specific and system resources that are available to your app, see XAML theme resources.

针对 XAML 资源引用的查找行为Lookup behavior for XAML resource references

查找行为是描述 XAML 资源系统如何尝试查找 XAML 资源的术语。Lookup behavior is the term that describes how the XAML resources system tries to find a XAML resource. 当键从应用的 XAML 的某处被引用为 XAML 资源引用时,即发生查找行为。The lookup occurs when a key is referenced as a XAML resource reference from somewhere in the app's XAML. 首先,资源系统具有可预测行为,它将为此类行为根据作用域检查是否存在资源。First, the resources system has predictable behavior for where it will check for the existence of a resource based on scope. 如果在初始作用域中未找到资源,该作用域将展开。If a resource isn't found in the initial scope, the scope expands. 将在应用或系统可能定义了 XAML 资源的位置和作用域上继续查找行为。The lookup behavior continues on throughout the locations and scopes that a XAML resource could possibly be defined by an app or by the system. 如果所有可能的资源查找尝试均失败,通常会导致错误。If all possible resource lookup attempts fail, an error often results. 通常可以在开发过程中消除这些错误。It's usually possible to eliminate these errors during the development process.

针对 XAML 资源引用的查找行为首先从应用实际用法的对象以及它自己的 Resources 属性开始。The lookup behavior for XAML resource references starts with the object where the actual usage is applied and its own Resources property. 如果此处存在 ResourceDictionary,则会检查该 ResourceDictionary 以查看其中是否存在具有所请求键的项。If a ResourceDictionary exists there, that ResourceDictionary is checked for an item that has the requested key. 该第一级查找很少包含相关信息,因为你通常不会在同一个对象上定义某个资源,然后引用该资源。This first level of lookup is rarely relevant because you usually do not define and then reference a resource on the same object. 实际上,Resources 属性通常不存在于此处。In fact, a Resources property often doesn't exist here. 你几乎可以在 XAML 中的任何位置进行 XAML 资源引用,而不限于在 FrameworkElement 子类的属性中。You can make XAML resource references from nearly anywhere in XAML; you aren't limited to properties of FrameworkElement subclasses.

查找序列随后检查应用的运行时对象树中的下一个父对象。The lookup sequence then checks the next parent object in the runtime object tree of the app. 如果存在一个 FrameworkElement.Resources 并且它持有一个 ResourceDictionary,将请求具有指定键字符串的字典项。If a FrameworkElement.Resources exists and holds a ResourceDictionary, the dictionary item with the specified key string is requested. 如果找到资源,查找序列就会停止,并将该对象提供到执行引用的位置。If the resource is found, the lookup sequence stops and the object is provided to the location where the reference was made. 否则,查找行为会向对象树根方向前进到下一个父级对象。Otherwise, the lookup behavior advances to the next parent level towards the object tree root. 此搜索会继续递归前进,直至到达 XAML 的根元素,从而完成对所有可能直接资源位置的搜索。The search continues recursively upwards until the root element of the XAML is reached, exhausting the search of all possible immediate resource locations.

注意  一种常见的做法是在页面的根级别定义所有直接资源,以利用该资源查找行为并将其用作 XAML 标记样式的一个惯例。Note  It is a common practice to define all the immediate resources at the root level of a page, both to take advantage of this resource-lookup behavior and also as a convention of XAML markup style.

如果未在直接资源中找到所请求的资源,下一个查找步骤是检查 Application.Resources 属性。If the requested resource is not found in the immediate resources, the next lookup step is to check the Application.Resources property. Application.Resources 是放置由应用导航结构中多个页面引用的任何应用特定资源的最佳位置。Application.Resources is the best place to put any app-specific resources that are referenced by multiple pages in your app's navigation structure.

在引用查找中,控件模板有另一个可能的位置:主题字典。Control templates have another possible location in the reference lookup: theme dictionaries. 主题字典是单个 XAML 文件,它具有一个 ResourceDictionary 元素作为其根。A theme dictionary is a single XAML file that has a ResourceDictionary element as its root. 主题字典可能是来自 Application.Resources 的一个合并字典。The theme dictionary might be a merged dictionary from Application.Resources. 主题字典也可能是一个特定于控件的主题字典,用于模板化的自定义控件。The theme dictionary might also be the control-specific theme dictionary for a templated custom control.

最后,还有一种针对平台资源的资源查找。Finally, there is a resource lookup against platform resources. 平台资源包括为每个系统 UI 主题定义的控件模板,以及用于定义你在 Windows 运行时应用中为所有 UI 控件使用的默认外观的控件模板。Platform resources include the control templates that are defined for each of the system UI themes, and which define the default appearance of all the controls that you use for UI in a Windows Runtime app. 平台资源还包括与系统范围内的外观和主题相关的一组已命名资源。Platform resources also include a set of named resources that relate to system-wide appearance and themes. 从技术上来说,这些资源是 MergedDictionaries 项,因此在加载应用之后可用于从 XAML 或代码中查找。These resources are technically a MergedDictionaries item, and thus are available for lookup from XAML or code once the app has loaded. 例如,系统主题资源包括一个名为 “SystemColorWindowTextColor”的资源,该资源提供一个 Color 定义以使应用文本颜色与系统窗口的文本颜色(来自操作系统和用户首选项)相匹配。For example, the system theme resources include a resource named "SystemColorWindowTextColor" that provides a Color definition to match app text color to a system window's text color that comes from the operating system and user preferences. 应用的其他 XAML 样式可以引用该样式,或者你的代码可以获取资源查找值(并将该值转换为示例中的 Color)。Other XAML styles for your app can refer to this style, or your code can get a resource lookup value (and cast it to Color in the example case).

有关特定于主题的资源和系统资源(可用于使用 XAML 的 UWP 应用)的详细信息和列表,请参阅 XAML 主题资源For more info and for a list of the theme-specific and system resources that are available to a UWP app that uses XAML, see XAML theme resources.

如果请求的键仍未在这其中任何位置中找到,会发生 XAML 分析错误/异常。If the requested key is still not found in any of these locations, a XAML parsing error/exception occurs. 某些情况下,XAML 分析异常可能是 XAML 标记编译操作或 XAML 设计环境未检测到的运行时异常。In certain circumstances, the XAML parse exception may be a run-time exception that is not detected either by a XAML markup compile action, or by a XAML design environment.

根据针对资源字典的分层查找行为,你可特意定义多个资源项,每个资源项使用相同的字符串值作为键,只要将每个资源定义在不同的级别上即可。Because of the tiered lookup behavior for resource dictionaries, you can deliberately define multiple resource items that each have the same string value as the key, as long as each resource is defined at a different level. 换言之,尽管键在任何给定的 ResourceDictionary 中必须是唯一的,但该唯一性要求不会扩展到整个查找行为序列。In other words, although keys must be unique within any given ResourceDictionary, the uniqueness requirement does not extend to the lookup behavior sequence as a whole. 在查找过程中,只有成功检索到的首个此类对象会用于 XAML 资源引用,随即查找便会停止。During lookup, only the first such object that's successfully retrieved is used for the XAML resource reference, and then the lookup stops. 你可以利用此行为在应用 XAML 内的各个位置通过键请求相同的 XAML 资源,但会取回不同的资源,具体取决于进行 XAML 资源引用的范围以及特殊查找的行为方式。You could use this behavior to request the same XAML resource by key at various positions within your app's XAML but get different resources back, depending on the scope from which the XAML resource reference was made and how that particular lookup behaves.

ResourceDictionary 中的前向引用Forward references within a ResourceDictionary

一个特定资源字典中的 XAML 资源引用必须引用定义了键的资源,并且从字典顺序来讲,该资源必须出现在资源引用之前。XAML resource references within a particular resource dictionary must reference a resource that has already been defined with a key, and that resource must appear lexically before the resource reference. XAML 资源引用无法解析前向引用。Forward references cannot be resolved by a XAML resource reference. 出于此原因,如果你从另一个资源内使用 XAML 资源引用,则必须设计资源字典结构,以便使其他资源使用的资源在资源字典中首先定义。For this reason, if you use XAML resource references from within another resource, you must design your resource dictionary structure so that the resources that are used by other resources are defined first in a resource dictionary.

在应用级别定义的资源不能引用直接资源。Resources defined at the app level cannot make references to immediate resources. 这相当于尝试前向引用,因为应用资源实际上最先被处理(在应用首次启动和加载任意导航页内容之前)。This is equivalent to attempting a forward reference, because the app resources are actually processed first (when the app first starts, and before any navigation-page content is loaded). 但是,任何直接资源都可引用应用资源,这可以作为避免前向引用情形的一种有用技术。However, any immediate resource can make a reference to an app resource, and this can be a useful technique for avoiding forward-reference situations.

XAML 资源必须可共享XAML resources must be shareable

要使对象可存在于 ResourceDictionary 中,该对象必须可共享For an object to exist in a ResourceDictionary, that object must be shareable.

可共享是必要的,因为在构造以及在运行时使用应用的对象树时,对象不能存在于树中的多个位置。Being shareable is required because, when the object tree of an app is constructed and used at run time, objects cannot exist at multiple locations in the tree. 就内部而言,在请求所有 XAML 资源时,资源系统会为在资源的对象图中使用的资源值创建副本。Internally, the resource system creates copies of resource values to use in the object graph of your app when each XAML resource is requested.

通常,ResourceDictionary 和 Windows 运行时 XAML 支持将下列对象用于共享:A ResourceDictionary and Windows Runtime XAML in general supports these objects for shareable usage:

此外,如果遵循必要的实现模式,则可将自定义类型用作可共享资源。You can also use custom types as a shareable resource if you follow the necessary implementation patterns. 在支持代码(或所含运行时组件)中定义这些类,然后在 XAML 中将其实例化为资源。You define such classes in your backing code (or in runtime components that you include) and then instantiate those classes in XAML as a resource. 示例包括对象数据源和用于数据绑定的 IValueConverter 实现。Examples are object data sources and IValueConverter implementations for data binding.

自定义类型必须包含默认构造函数,因为 XAML 分析程序须借助该构造函数对类进行实例化。Custom types must have a default constructor, because that's what a XAML parser uses to instantiate a class. 用作资源的自定义类型不能在其继承中包含 UIElement 类,因为 UIElement 无法共享(而只能一直用于表示运行时应用的对象图中某一位置中存在的一个 UI 元素)。Custom types used as resources can't have the UIElement class in their inheritance, because a UIElement can never be shareable (it's always intended to represent exactly one UI element that exists at one position in the object graph of your runtime app).

UserControl 使用范围UserControl usage scope

对于资源查找行为,UserControl 元素有一个特殊情况,因为它有一个定义范围和使用范围的固有概念。A UserControl element has a special situation for resource-lookup behavior because it has the inherent concepts of a definition scope and a usage scope. 从其定义范围内进行 XAML 资源引用的 UserControl 必须能够支持在其自己的定义范围查找序列中查找该资源,也就是说,它不能访问应用资源。A UserControl that makes a XAML resource reference from its definition scope must be able to support the lookup of that resource within its own definition-scope lookup sequence—that is, it cannot access app resources. UserControl 使用范围中,将资源引用视为在朝向其使用页面根方向的查询序列内(就像从加载的对象树中的一个对象执行的任何其他资源引用一样),并且可访问应用资源。From a UserControl usage scope, a resource reference is treated as being within the lookup sequence towards its usage page root (just like any other resource reference made from an object in a loaded object tree) and can access app resources.

ResourceDictionary 和 XamlReader.LoadResourceDictionary and XamlReader.Load

你可以将 ResourceDictionary 用作根或用作 XamlReader.Load 方法的 XAML 输入的一部分。You can use a ResourceDictionary as either the root or a part of the XAML input for the XamlReader.Load method. 你还可以在该 XAML 中包含 XAML 资源引用(如果所有此类引用都完全自包含在为了加载而提交的 XAML 中)。You can also include XAML resource references in that XAML if all such references are completely self-contained in the XAML submitted for loading. XamlReader.Load 在不了解任何其他 ResourceDictionary 对象(甚至不了解 Application.Resources)的上下文中分析 XAML。XamlReader.Load parses the XAML in a context that is not aware of any other ResourceDictionary objects, not even Application.Resources. 此外,请不要从 XAML 内部使用提交到 XamlReader.Load{ThemeResource}Also, don't use {ThemeResource} from within XAML submitted to XamlReader.Load.

通过代码使用 ResourceDictionaryUsing a ResourceDictionary from code

大部分情况下,ResourceDictionary 均在 XAML 中专门处理。Most of the scenarios for a ResourceDictionary are handled exclusively in XAML. 你要在 UI 定义文件中将内部的 ResourceDictionary 容器和资源声明为 XAML 文件或 XAML 节点集。You declare the ResourceDictionary container and the resources within as a XAML file or set of XAML nodes in a UI definition file. 然后,使用 XAML 资源引用从 XAML 的其他部分请求这些资源。And then you use XAML resource references to request those resources from other parts of XAML. 不过,在某些特定情况下,你的应用可能需要使用在应用运行时执行的代码来调整 ResourceDictionary 的内容,或者至少需要查询 ResourceDictionary 的内容以查看是否已定义某个资源。Still, there are certain scenarios where your app might want to adjust the contents of a ResourceDictionary using code that executes while the app is running, or at least to query the contents of a ResourceDictionary to see if a resource is already defined. 这些代码调用在 ResourceDictionary 实例上执行,所以必须首先通过获得 FrameworkElement.Resources 来检索对象树中的即时 ResourceDictionary,或者检索 Application.Current.ResourcesThese code calls are made on a ResourceDictionary instance, so you must first retrieve one—either an immediate ResourceDictionary somewhere in the object tree by getting FrameworkElement.Resources, or Application.Current.Resources.

在 C# 或 Microsoft Visual Basic 代码中,你可以使用索引器 (Item) 引用给定 ResourceDictionary 中的资源。In C# or Microsoft Visual Basic code, you can reference a resource in a given ResourceDictionary by using the indexer (Item). ResourceDictionary 是一个字符串键控字典,因此索引器使用字符串键,而不使用整数索引。A ResourceDictionary is a string-keyed dictionary, so the indexer uses the string key instead of an integer index. 在 Visual C++ 组件扩展 (C++/CX) 代码中,请使用 LookupIn Visual C++ component extensions (C++/CX) code, use Lookup.

当使用代码检查或更改 ResourceDictionary 时,API 的行为(如 LookupItem)不会从直接资源遍历到应用资源;这是仅在加载 XAML 页面时发生的 XAML 分析程序行为。When using code to examine or change a ResourceDictionary, the behavior for APIs like Lookup or Item does not traverse from immediate resources to app resources; that's a XAML parser behavior that only happens as XAML pages are loaded. 在运行时,键作用域将自包含到此时所使用的 ResourceDictionary 实例中。At run time, scope for keys is self-contained to the ResourceDictionary instance that you are using at the time. 但是,该作用域不会扩展到 MergedDictionaries 中。However, that scope does extend into MergedDictionaries.

另外,如果你请求的键不在 ResourceDictionary 中,可能不会出现错误;但返回值可能只会提供为 nullAlso, if you request a key that does not exist in the ResourceDictionary, there may not be an error; the return value may simply be provided as null. 但是,如果你尝试将返回的 null 用作值,仍然可能会出现错误。You may still get an error, though, if you try to use the returned null as a value. 错误可能来自于属性的设置器,而不是你的 ResourceDictionary 调用。The error would come from the property's setter, not your ResourceDictionary call. 避免错误的唯一方法是属性接受 null 作为有效值。The only way you'd avoid an error is if the property accepted null as a valid value. 请注意此行为与 XAML 解析期间的 XAML 查找行为有何区别;如果在解析期间无法解析从 XAML 提供的键,会导致 XAML 解析错误,甚至在属性可以接受 null 时也是如此。Note how this behavior contrasts with XAML lookup behavior at XAML parse time; a failure to resolve the provided key from XAML at parse time results in a XAML parse error, even in cases where the property could have accepted null.

合并的资源字典包含在主要资源字典的索引范围内,该字典在运行时引用合并字典。Merged resource dictionaries are included into the index scope of the primary resource dictionary that references the merged dictionary at run time. 换句话说,可以使用主要字典的 ItemLookup 查找在合并字典中实际定义的任何对象。In other words, you can use Item or Lookup of the primary dictionary to find any objects that were actually defined in the merged dictionary. 在这种情况下,该查找行为类似于分析期间的 XAML 查找行为:如果合并字典中存在多个具有相同键的对象,将返回最后添加的字典中的对象。In this case, the lookup behavior does resemble the parse-time XAML lookup behavior: if there are multiple objects in merged dictionaries that each have the same key, the object from the last-added dictionary is returned.

你可以通过调用 Add(C# 或 Visual Basic)或 Insert (C++/CX) 向现有的 ResourceDictionary 添加项。You are permitted to add items to an existing ResourceDictionary by calling Add (C# or Visual Basic) or Insert (C++/CX). 你可以将这些项添加到直接资源或应用资源。You could add the items to either immediate resources or app resources. 这些 API 调用中的每一个都需要一个键,这满足 ResourceDictionary 中的每个项都必须有一个键的要求。Either of these API calls requires a key, which satisfies the requirement that each item in a ResourceDictionary must have a key. 但是,你在运行时添加到 ResourceDictionary 的项与 XAML 资源引用无关。However, items that you add to a ResourceDictionary at run time are not relevant to XAML resource references. 在加载应用后首次分析 XAML 时,将执行必要的 XAML 资源引用查找。The necessary lookup for XAML resource references happens when that XAML is first parsed as the app is loaded (or a theme change is detected). 此时,在运行时添加到集合的资源不可用,而更改 ResourceDictionary 并不会使已从中检索到的资源失效,即使更改该资源的值也是如此。Resources added to collections at run time weren't available then, and altering the ResourceDictionary doesn't invalidate an already retrieved resource from it even if you change the value of that resource.

你还可以在运行时从某个 ResourceDictionary 删除项、复制部分或所有项,或执行其他操作。You also can remove items from a ResourceDictionary at run time, make copies of some or all items, or other operations. ResourceDictionary 的成员列表指出了哪些 API 可用。The members listing for ResourceDictionary indicates which APIs are available. 请注意,由于 ResourceDictionary 有一个投影的 API 可支持其基本集合接口,因此你的 API 选项会有所不同,具体取决于你使用的是 C# 或 Visual Basic 还是 C++/CX。Note that because ResourceDictionary has a projected API to support its underlying collection interfaces, your API options differ depending on whether you are using C# or Visual Basic versus C++/CX.

ResourceDictionary 和本地化ResourceDictionary and localization

XAML ResourceDictionary 最初可能包含要本地化的字符串。A XAML ResourceDictionary might initially contain strings that are to be localized. 如果是这样,将这些字符串存储为项目资源,而不存储在 ResourceDictionary 中。If so, store these strings as project resources instead of in a ResourceDictionary. 将字符串放在 XAML 外部,而为拥有元素提供一个 x:Uid 指令值。Take the strings out of the XAML, and instead give the owning element an x:Uid directive value. 然后,在资源文件中定义一个资源。Then, define a resource in a resources file. XUIDValue.PropertyName 的形式提供资源名称,并提供应该本地化的字符串的资源值。Provide a resource name in the form XUIDValue.PropertyName and a resource value of the string that should be localized.

自定义资源查找Custom resource lookup

对于高级方案,你可以实现其行为不同于本主题中描述的 XAML 资源引用查找行为的类。For advanced scenarios, you can implement a class that can have different behavior than the XAML resource reference lookup behavior described in this topic. 要达到此目的,你可实现类 CustomXamlResourceLoader,然后可以通过使用 CustomResource 标记扩展进行资源引用(而不是使用 StaticResourceThemeResource)来实现该行为。To do this, you implement the class CustomXamlResourceLoader, and then you can access that behavior by using the CustomResource markup extension for resource references rather than using StaticResource or ThemeResource. 大部分应用的方案将不会需要此操作。Most apps won't have scenarios that require this. 有关详细信息,请参阅 CustomXamlResourceLoaderFor more info, see CustomXamlResourceLoader.