资源字典

.NET 多平台应用 UI (.NET MAUI) ResourceDictionary 是 .NET MAUI 应用使用的资源存储库。 存储在 中 ResourceDictionary 的典型资源包括样式、控件模板、数据模板、转换器和颜色。

可以使用 或 DynamicResource 标记扩展引用存储在 中的 ResourceDictionary XAML 资源并将其应用于元素StaticResource。 在 C# 中,还可以在 中 ResourceDictionary 定义资源,然后使用基于字符串的索引器引用并应用于元素。 但是,在 C# 中使用 ResourceDictionary 没有什么好处,因为共享对象可以存储为字段或属性,并直接访问,而无需先从字典中检索它们。

提示

在 Visual Studio 中,可以通过 .NET MAUI ResourceDictionary (XAML) 项模板将代码隐藏文件支持的基于 ResourceDictionary XAML 的文件添加到项目中。

创建资源

每个 VisualElement 派生对象都有一个 Resources 属性,该属性是 ResourceDictionary 可以包含资源的 。 同样, Application 派生对象具有 属性 Resources ,该属性是 ResourceDictionary 可以包含资源的 。

.NET MAUI 应用只能包含派生自 Application的单个类,但通常使用许多派生自 VisualElement的类,包括页面、布局和视图。 这些对象中的任何一个都可以将其 Resources 属性设置为 ResourceDictionary 包含的资源。 选择将特定 ResourceDictionary 影响置于可使用资源的位置:

除隐式样式外,资源字典中的每个资源都必须具有使用 x:Key 属性定义的唯一字符串键。

以下 XAML 显示在 App.xaml 文件中的应用程序级别ResourceDictionary中定义的资源:

<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ResourceDictionaryDemo.App">
    <Application.Resources>

        <Thickness x:Key="PageMargin">20</Thickness>

        <!-- Colors -->
        <Color x:Key="AppBackgroundColor">AliceBlue</Color>
        <Color x:Key="NavigationBarColor">#1976D2</Color>
        <Color x:Key="NavigationBarTextColor">White</Color>
        <Color x:Key="NormalTextColor">Black</Color>

        <!-- Implicit styles -->
        <Style TargetType="NavigationPage">
            <Setter Property="BarBackgroundColor"
                    Value="{StaticResource NavigationBarColor}" />
            <Setter Property="BarTextColor"
                    Value="{StaticResource NavigationBarTextColor}" />
        </Style>

        <Style TargetType="ContentPage"
               ApplyToDerivedTypes="True">
            <Setter Property="BackgroundColor"
                    Value="{StaticResource AppBackgroundColor}" />
        </Style>

    </Application.Resources>
</Application>

在此示例中,资源字典定义了一个 Thickness 资源、多个 Color 资源和两个隐式 Style 资源。

重要

直接在 Resources 属性元素标记之间插入资源会自动创建 ResourceDictionary 对象。 但是,在可选 ResourceDictionary 标记之间放置所有资源也是有效的。

使用资源

每个资源都有一个使用 x:Key 特性指定的键,该键将成为其在 中的 ResourceDictionary字典键。 键用于使用 或 DynamicResource XAML 标记扩展从 ResourceDictionaryStaticResource 引用资源。

标记 StaticResource 扩展类似于标记扩展, DynamicResource 两者都使用字典键引用资源字典中的值。 但是,当 StaticResource 标记扩展执行单个字典查找时 DynamicResource ,标记扩展会保留指向字典键的链接。 因此,如果替换了与键关联的字典条目,则更改将应用于可视元素。 这允许在应用中进行运行时资源更改。 有关标记扩展的详细信息,请参阅 XAML 标记扩展

以下 XAML 示例演示如何使用资源,以及如何在 中 StackLayout定义其他资源:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ResourceDictionaryDemo.MainPage"
             Title="Main page">
    <StackLayout Margin="{StaticResource PageMargin}"
                 Spacing="6">
        <StackLayout.Resources>
            <!-- Implicit style -->
            <Style TargetType="Button">
                <Setter Property="FontSize" Value="14" />
                <Setter Property="BackgroundColor" Value="#1976D2" />
                <Setter Property="TextColor" Value="White" />
                <Setter Property="CornerRadius" Value="5" />
            </Style>
        </StackLayout.Resources>

        <Label Text="This app demonstrates consuming resources that have been defined in resource dictionaries." />
        <Button Text="Navigate"
                Clicked="OnNavigateButtonClicked" />
    </StackLayout>
</ContentPage>

在此示例中, ContentPage 对象使用应用程序级别资源字典中定义的隐式样式。 对象 StackLayout 使用 PageMargin 应用程序级别资源字典中定义的资源,而 Button 对象使用资源字典中 StackLayout 定义的隐式样式。 这会导致以下屏幕截图中显示的外观:

使用资源字典资源。

重要

特定于单个页面的资源不应包含在应用程序级别资源字典中,因为此类资源将在应用启动时进行分析,而不是在页面需要时分析。

资源查找行为

使用 或 DynamicResource 标记扩展引用资源时,StaticResource会发生以下查找过程:

  • 对于设置 属性的元素,在资源字典中检查请求的键(如果存在)。 如果找到请求的键,则返回其值,并且查找过程将终止。
  • 如果未找到匹配项,查找过程将向上搜索可视化树,并检查每个父元素的资源字典。 如果找到请求的键,则返回其值,并且查找过程将终止。 否则,该过程会向上继续,直到到达根元素。
  • 如果在根元素中找不到匹配项,则会检查应用程序级资源字典。
  • 如果仍未找到匹配项, XamlParseException 则会引发 。

因此,当 XAML 分析程序遇到 StaticResourceDynamicResource 标记扩展时,它将通过使用它找到的第一个匹配项在可视化树中向上移动来搜索匹配键。 如果此搜索在页面结束,但仍未找到该键,则 XAML 分析程序将搜索 ResourceDictionary 附加到对象的 App 。 如果仍未找到密钥,则会引发异常。

替代资源

当资源共享密钥时,在可视化树中较低位置定义的资源将优先于上一级定义的资源。 例如,在应用程序级别将资源设置为 AppBackgroundColorAliceBlue 将被设置为 Teal的页面级别AppBackgroundColor资源替代。 同样,页面级别 AppBackgroundColor 资源将被布局或视图级别 AppBackgroundColor 资源替代。

独立资源字典

ResourceDictionary还可以创建为不受代码隐藏文件支持的独立 XAML 文件。 若要创建独立 ResourceDictionary,请使用 .NET MAUI ResourceDictionary (XAML) 项模板向项目添加新ResourceDictionary文件,并删除其代码隐藏文件。 然后,在 XAML 文件中, x:ClassResourceDictionary 文件开头附近的 标记中删除 属性。 此外,在 XML 标头后面添加 <?xaml-comp compile="true" ?> ,以确保将编译 XAML。

注意

独立 ResourceDictionary 版必须具有 MauiXaml 的生成操作。

以下 XAML 示例显示了名为 MyResourceDictionary.xaml 的独立ResourceDictionary示例:

<?xml version="1.0" encoding="UTF-8" ?>
<?xaml-comp compile="true" ?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
    <DataTemplate x:Key="PersonDataTemplate">
        <ViewCell>
            <Grid RowSpacing="6"
                  ColumnSpacing="6">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="0.5*" />
                    <ColumnDefinition Width="0.2*" />
                    <ColumnDefinition Width="0.3*" />
                </Grid.ColumnDefinitions>
                <Label Text="{Binding Name}"
                       TextColor="{StaticResource NormalTextColor}"
                       FontAttributes="Bold" />
                <Label Grid.Column="1"
                       Text="{Binding Age}"
                       TextColor="{StaticResource NormalTextColor}" />
                <Label Grid.Column="2"
                       Text="{Binding Location}"
                       TextColor="{StaticResource NormalTextColor}"
                       HorizontalTextAlignment="End" />
            </Grid>
        </ViewCell>
    </DataTemplate>
</ResourceDictionary>

在此示例中, ResourceDictionary 包含单个资源,该资源是 类型的 DataTemplate对象。 MyResourceDictionary.xaml 可以通过将其合并到另一个资源字典来使用。

合并资源字典

可以通过将一个或多个 ResourceDictionary 对象合并到另一个 ResourceDictionary来组合资源字典。

合并本地资源字典

可以通过创建一个 对象,将本地 ResourceDictionary 文件合并到另一 ResourceDictionaryResourceDictionary 文件中,该对象的属性 Source 设置为具有资源的 XAML 文件的文件名:

<ContentPage ...>
    <ContentPage.Resources>
        <!-- Add more resources here -->
        <ResourceDictionary Source="MyResourceDictionary.xaml" />
        <!-- Add more resources here -->
    </ContentPage.Resources>
    ...
</ContentPage>

此语法不会实例化 MyResourceDictionary 类。 而是引用 XAML 文件。 因此,在设置 Source 属性时,不需要代码隐藏文件, x:Class 并且可以从 MyResourceDictionary.xaml 文件的根标记中删除该属性。

重要

只能 ResourceDictionary.Source 从 XAML 设置 属性。

从其他程序集合并资源字典

ResourceDictionary还可以通过将 添加到 的 ResourceDictionary属性,将其合并到另MergedDictionaries一个 ResourceDictionary 。 此方法允许合并资源字典,而不考虑资源字典所在的程序集。 从外部程序集合并资源字典需要 ResourceDictionary 将生成操作设置为 MauiXaml,具有代码隐藏文件,并在文件的根标记中定义 x:Class 属性。

警告

ResourceDictionary 类还会定义一个 MergedWith 属性。 但是,此属性已弃用,不应再使用。

下面的代码示例演示将两个资源字典添加到 MergedDictionaries 页面级别的 ResourceDictionary集合中:

<ContentPage ...
             xmlns:local="clr-namespace:ResourceDictionaryDemo"
             xmlns:theme="clr-namespace:MyThemes;assembly=MyThemes">
    <ContentPage.Resources>
        <ResourceDictionary>
            <!-- Add more resources here -->
            <ResourceDictionary.MergedDictionaries>
                <!-- Add more resource dictionaries here -->
                <local:MyResourceDictionary />
                <theme:DefaultTheme />
                <!-- Add more resource dictionaries here -->
            </ResourceDictionary.MergedDictionaries>
            <!-- Add more resources here -->
        </ResourceDictionary>
    </ContentPage.Resources>
    ...
</ContentPage>

在此示例中,同一程序集中的资源字典和外部程序集中的资源字典合并到页级资源字典中。 此外,还可以在属性元素标记内MergedDictionaries添加其他ResourceDictionary对象,以及这些标记之外的其他资源。

重要

中只能有一个MergedDictionariesResourceDictionary属性元素标记,但可以根据需要在其中放置任意数量的ResourceDictionary对象。

当合并 ResourceDictionary 的资源共享相同的 x:Key 属性值时,.NET MAUI 使用以下资源优先级:

  1. 资源字典的本地资源。
  2. 通过 MergedDictionaries 集合合并的资源字典中包含的资源,其顺序与 属性中的 MergedDictionaries 列出顺序相反。

提示

如果应用包含多个大型资源字典,则搜索资源字典可能是一项计算密集型任务。 因此,为了避免不必要的搜索,应确保应用程序中的每一页仅使用适合该页的资源字典。