借助 .NET Multi-platform App UI (.NET MAUI) XAML 标记扩展,可以将属性设置为通过其他源间接引用的对象或值。 XAML 标记扩展对于共享对象和引用要在整个应用中使用的常量尤为重要,但它们在数据绑定中可以发挥最大用处。
通常,使用 XAML 将对象的属性设置为显式值,例如字符串、数字、枚举成员或在后台转换为值的字符串。 有时,属性需要引用在其他位置定义的值,或者在运行时需要通过代码进行处理的值。 为此,可使用 XAML 标记扩展。
XAML 标记扩展之所以如此命名,是因为它们由实现 IMarkupExtension 的类中的代码提供支持。 也可以自行编写自定义标记扩展。
许多时候,XAML 标记扩展在 XAML 文件中一眼就能识别,因为它们以特性值的形式出现,并用大括号 { } 分隔,但有时标记扩展也会以传统元素形式出现在标记中。
重要
标记扩展可以具有属性,但却不像 XML 特性那样设置。 在标记扩展中,设置属性时用逗号分隔,大括号内不用引号。
共享资源
某些 XAML 页面包含多个视图,这些视图的属性设置为相同的值。 例如,这些 Button 对象的许多属性设置是相同的:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SharedResourcesPage"
Title="Shared Resources Page">
<StackLayout>
<Button Text="Do this!"
HorizontalOptions="Center"
VerticalOptions="Center"
BorderWidth="3"
Rotation="-15"
TextColor="Red"
FontSize="24" />
<Button Text="Do that!"
HorizontalOptions="Center"
VerticalOptions="Center"
BorderWidth="3"
Rotation="-15"
TextColor="Red"
FontSize="24" />
<Button Text="Do the other thing!"
HorizontalOptions="Center"
VerticalOptions="Center"
BorderWidth="3"
Rotation="-15"
TextColor="Red"
FontSize="24" />
</StackLayout>
</ContentPage>
如果需要更改其中一个属性,你可能更愿意只更改一次,而不是更改三次。 如果这是代码,你可能会使用常量和静态只读对象来帮助保持此类值一致和便于修改。
在 XAML 中,一种常用的解决方案是将此类值或对象存储在资源字典中。
VisualElement 类定义了一个属性,名为 Resources,其类型为 ResourceDictionary,这是一个字典,键的类型为 string,值的类型为 object。 可以将对象放入此字典,然后通过标记引用它们,全部操作都在 XAML 中完成。
要在页面上使用资源字典,可在页面顶部加入一对 Resources 属性元素标签,并在这些标签中添加资源。 各种类型的对象和值都可以添加到资源字典中。 这些类型必须可实例化。 例如,它们不能是抽象类。 这些类型还必须具有公共无参数构造函数。 每个项都需要一个由 x:Key 属性指定的字典键:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SharedResourcesPage"
Title="Shared Resources Page">
<ContentPage.Resources>
<LayoutOptions x:Key="horzOptions"
Alignment="Center" />
<LayoutOptions x:Key="vertOptions"
Alignment="Center" />
</ContentPage.Resources>
...
</ContentPage>
在此示例中,两个资源的结构类型为LayoutOptions,每个资源都有一个唯一键,并设置了一或两个属性。 在代码和标记中,更常用 LayoutOptions 的静态字段,但在此处设置属性更为方便。
注意
可选的 ResourceDictionary 标签可以作为 Resources 标签的子项包含在内。
然后 Button 对象可以使用这些资源,方法是使用 StaticResource XAML 标记扩展来设置它们的 HorizontalOptions 和 VerticalOptions 属性。
<Button Text="Do this!"
HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="3"
Rotation="-15"
TextColor="Red"
FontSize="24" />
StaticResource 标记扩展始终用大括号分隔,并包含字典键。 名称StaticResource将其与DynamicResource区分开来,.NET MAUI 也支持这两个选项。 DynamicResource 用于与运行时可能更改的值相关联的字典键,而 StaticResource 仅在构造页面元素时访问一次字典中的元素。 每当 XAML 分析器遇到一个 `StaticResource` 标记扩展时,它会向上搜索可视化树,并使用它在该树中找到的第一个包含该键的 `ResourceDictionary`。
需要在字典中为 BorderWidth、Rotation 和 FontSize 属性存储 double 类型的值。 XAML 可轻松为常见数据类型定义标记,例如 x:Double 和 x:Int32:
<ContentPage.Resources>
<LayoutOptions x:Key="horzOptions"
Alignment="Center" />
<LayoutOptions x:Key="vertOptions"
Alignment="Center" />
<x:Double x:Key="borderWidth">3</x:Double>
<x:Double x:Key="rotationAngle">-15</x:Double>
<x:Double x:Key="fontSize">24</x:Double>
</ContentPage.Resources>
这三个额外资源的引用方式与 LayoutOptions 值一样:
<Button Text="Do this!"
HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="Red"
FontSize="{StaticResource fontSize}" />
对于类型Color的资源,可以使用与直接分配这些类型的属性时相同的字符串表示形式。 创建资源时会调用 .NET MAUI 中包含的类型转换器。 再可以在资源字典中使用 OnPlatform 类,根据平台定义不同的值。 以下示例使用此类设置不同文本颜色的步骤:
<OnPlatform x:Key="textColor"
x:TypeArguments="Color">
<On Platform="iOS" Value="Red" />
<On Platform="Android" Value="Aqua" />
</OnPlatform>
OnPlatform 资源得到一个 x:Key 属性(因为它是字典中的对象),以及一个 x:TypeArguments 属性(因为它是泛型类)。 初始化对象时,iOS 和 Android 属性将转换为 Color 值。
以下示例显示了访问六个共享值的三个按钮:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SharedResourcesPage"
Title="Shared Resources Page">
<ContentPage.Resources>
<LayoutOptions x:Key="horzOptions"
Alignment="Center" />
<LayoutOptions x:Key="vertOptions"
Alignment="Center" />
<x:Double x:Key="borderWidth">3</x:Double>
<x:Double x:Key="rotationAngle">-15</x:Double>
<x:Double x:Key="fontSize">24</x:Double>
<OnPlatform x:Key="textColor"
x:TypeArguments="Color">
<On Platform="iOS" Value="Red" />
<On Platform="Android" Value="Aqua" />
<On Platform="WinUI" Value="#80FF80" />
</OnPlatform>
</ContentPage.Resources>
<StackLayout>
<Button Text="Do this!"
HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="{StaticResource textColor}"
FontSize="{StaticResource fontSize}" />
<Button Text="Do that!"
HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="{StaticResource textColor}"
FontSize="{StaticResource fontSize}" />
<Button Text="Do the other thing!"
HorizontalOptions="{StaticResource horzOptions}"
VerticalOptions="{StaticResource vertOptions}"
BorderWidth="{StaticResource borderWidth}"
Rotation="{StaticResource rotationAngle}"
TextColor="{StaticResource textColor}"
FontSize="{StaticResource fontSize}" />
</StackLayout>
</ContentPage>
以下屏幕截图证实了一致的样式:
虽然通常在页面顶部定义 Resources 集合,页面的其他元素上也可以设置 Resources 集合。 例如,以下示例显示了资源添加到 StackLayout 的方式:
<StackLayout>
<StackLayout.Resources>
<Color x:Key="textColor">Blue</Color>
</StackLayout.Resources>
...
</StackLayout>
资源字典中存储的最常见对象类型之一是 .NET MAUI Style,它定义了一系列属性设置。 有关样式的详细信息,请参阅使用 XAML 设置应用程序样式。
x:Static 标记扩展
除了 StaticResource 标记扩展,还有一个 x:Static 标记扩展。 但是,StaticResource 返回资源字典中的对象,而 x:Static 访问公共静态字段、公共静态属性、公共常量字段或枚举成员。
注意
支持StaticResource标记扩展的 XAML 实现定义了一个资源字典,而x:Static是 XAML 的固有部分,正如x前缀所示。
以下示例演示 x:Static 如何显式引用静态字段和枚举成员:
<Label Text="Hello, XAML!"
VerticalOptions="{x:Static LayoutOptions.Start}"
HorizontalTextAlignment="{x:Static TextAlignment.Center}"
TextColor="{x:Static Colors.Aqua}" />
x:Static 标记扩展的主要用途是引用你自己代码中的静态字段或属性。 例如,这里有一个AppConstants类,其中包含一些可能需要在应用程序的多个页面中使用的静态字段:
namespace XamlSamples
{
static class AppConstants
{
public static readonly Color BackgroundColor = Colors.Aqua;
public static readonly Color ForegroundColor = Colors.Brown;
}
}
要在 XAML 文件中引用此类的静态字段,需要使用 XML 命名空间声明来指示此文件所在的位置。 每个附加的 XML 命名空间声明定义一个新前缀。 要访问根应用命名空间的本地类(如 `AppConstants`),可以使用前缀 `local`。 命名空间声明必须指示 CLR(公共语言运行时)命名空间名称,也称为 .NET 命名空间名称,该名称出现在 C# 的namespace定义或using指令中。
xmlns:local="clr-namespace:XamlSamples"
还可以为 .NET 命名空间定义 XML 命名空间声明。 例如,这里有一个 sys 前缀用于标准 .NET System 命名空间,该命名空间位于 netstandard 程序集中。 由于这是另一个程序集,还必须指定程序集名称,在本例中为 netstandard:
xmlns:sys="clr-namespace:System;assembly=netstandard"
注意
关键字 clr-namespace 后跟冒号,然后是 .NET 命名空间名称,再接着是分号、关键字 assembly、等号和程序集名称。
然后可在声明 XML 命名空间后使用静态字段:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples"
xmlns:sys="clr-namespace:System;assembly=netstandard"
x:Class="XamlSamples.StaticConstantsPage"
Title="Static Constants Page"
Padding="5,25,5,0">
<StackLayout>
<Label Text="Hello, XAML!"
TextColor="{x:Static local:AppConstants.BackgroundColor}"
BackgroundColor="{x:Static local:AppConstants.ForegroundColor}"
FontAttributes="Bold"
FontSize="30"
HorizontalOptions="Center" />
<BoxView WidthRequest="{x:Static sys:Math.PI}"
HeightRequest="{x:Static sys:Math.E}"
Color="{x:Static local:AppConstants.ForegroundColor}"
HorizontalOptions="Center"
VerticalOptions="Center"
Scale="100" />
</StackLayout>
</ContentPage>
在此示例中,BoxView 尺寸设置为 Math.PI 和 Math.E,但缩放比例为 100 倍:
使用 x:Static 标记扩展的控件示例的屏幕截图。
其他标记扩展
有多个标记扩展是 XAML 固有的,并且在 .NET MAUI XAML 中受支持。 其中有些并不常用,但在需要时却是必不可少的:
- 如果一个属性默认有非
null的值,但你希望将其设置为null,可以将其设置为{x:Null}标记扩展。 - 如果属性是类型
Type,则可以使用标记扩展{x:Type someClass}将其分配给Type对象。 - 您可以使用
x:Array标记扩展在 XAML 中定义数组。 此标记扩展包含一个名为Type的必需特性,用于指示数组中元素的类型。
有关 XAML 标记扩展的详细信息,请参阅XAML 标记扩展的使用。
后续步骤
.NET MAUI 数据绑定支持将两个对象的属性链接在一起,这样一个对象发生更改会引起另一个对象也发生更改。
浏览示例