创建和使用应用程序级资源

已完成

在 Extensible Application Markup Language (XAML) 页上定义资源和样式是减少重复代码的好方法。 但是有一个问题。 这些资源和样式仅在该特定 XAML 页上可用。 当有多个页面时,页面级资源字典不足以避免在应用程序中使用重复代码。 本单元介绍如何在 .NET Multi-Platform App UI (MAUI) 应用程序的所有页面中共享资源和样式。

资源字典在哪里可用

VisualElement 类定义了 Resources 属性。 控件、页面和布局都继承自 VisualElement,因此它们都有一个可保存资源字典的 Resources 属性。

Application 类也定义了 Resources 属性。 Application 不是从 VisualElement 中继承的,因此属性定义为该类的一部分。

下图演示了典型应用程序的结构。 显示的每个元素都有一个可保存资源字典的 Resources 属性。

注意

此图非常简要地描述了应用程序中的项目的组织方式。 在此关系图中,“视图”一词是指“按钮”或“标签”等单一控件,这种控件不充当任何子控件的容器。 此外,“布局”一词表示负责组织其子控件的布局的容器。 布局可以嵌套。 例如,“网格”控件可保存在“StackLayout”控件中。

关系图显示典型 .NET MAUI 应用程序的大致结构。

如何定义应用程序级资源和样式

在与 Application 类关联的 XAML 文件中定义应用程序级资源和样式。 以下代码演示如何在应用程序资源字典中声明“颜色”资源。

<Application.Resources>
    <Color x:Key="MyTextColor">Blue</Color>
</Application.Resources>

.NET MAUI 如何查找资源或样式

假设你将资源应用于其中一个控件,如以下代码所示。

<Label TextColor="{StaticResource MyTextColor}" ... />

.NET MAUI 需要找到该资源的定义,才能应用值。 一个应用程序可以拥有多个字典。 .NET MAUI 将以哪种顺序搜索哪些字典? 要回答这些问题,将页面上的 VisualElement 实例看作形成树状结构很有帮助。 应用程序位于根目录下,页面、布局和视图在其下方展开。 此结构通常称为“可视化树”。 树中的每个元素都可以拥有自己的字典,而字典可以包含资源。 .NET MAUI 中的样式搜索算法会遍历可视化树:

  1. 从资源所应用到的 VisualElement 实例中的字典中开始搜索。 在前面的示例中,以“标签”类型开始搜索。 如果没有资源字典,或者有字典但没有资源,则会继续搜索。

  2. 移至控件的父级,然后重复搜索。 通常,下一个要搜索的位置是布局。

  3. 检查布局的父级。 通常,下一个要搜索的位置是页面,但如果布局嵌套在另一个布局中(例如 StackLayout 中的“网格”内),则搜索将在树中向上移动到父级布局。

  4. 在字典中查找 Application 类。

搜索会返回首个匹配 x:Key 值的项。 下图总结了资源查找序列。

关系图显示 .NET 如何搜索资源。首先是视图,然后依次为布局、页面和应用程序。

实际上,大多数开发人员都忽略了视图和版式面板中的 Resources 属性。 他们将页面级字典用于在单个页面上使用的内容。 他们希望在多个页面上共享的资源和样式是在应用程序级别定义的。 查找过程随后只需检查两个字典:当前页面实例中的字典和应用程序中的字典。

注意

如果找不到具有指定键的资源,应用会使用默认值来设置样式。

重复键

每个 ResourceDictionary 实例都是独立的,这意味着可在多个字典中使用同一个 x:Key 值。 在搜索路径上的多个字典中使用相同的 x:Key 标识符不会导致错误。 使用的是与路径上首次匹配的 x:Key 值相关联的资源。

例如,假设在 Application 类中定义了以下资源:

<Application.Resources>
    <x:String x:Key="msg">Two</x:String>
</Application.Resources>

然后,在 ContentPage 中定义以下资源,并将其应用于同一页面上的 Label:

<ContentPage.Resources>
    <x:String x:Key="msg">One</x:String>
</ContentPage.Resources>
...
<Label Text="{StaticResource msg}">

使用了首次匹配的 x:Key 值,因此 Text 属性会设置为 One。