XAML 标记扩展
借助 .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
属性存储双精度值。 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
访问公共静态字段、公共静态属性、公共常量字段或枚举成员。
注意
定义资源字典的 XAML 实现支持 StaticResource
标记扩展,而 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 命名空间声明。 例如,下面是标准 .NET System
命名空间的 sys
前缀,位于 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="CenterAndExpand"
Scale="100" />
</StackLayout>
</ContentPage>
在此示例中,BoxView 尺寸设置为 Math.PI
和 Math.E
,但按 100 的比例进行了缩放:
其他标记扩展
有多个标记扩展是 XAML 固有的,并且在 .NET MAUI XAML 中受支持。 其中有些并不常用,但在需要时却是必不可少的:
- 如果属性默认具有非
null
值,但你想要将其设置为null
,则可将其设置为{x:Null}
标记扩展。 - 如果属性为
Type
类型,可使用标记扩展{x:Type someClass}
将其分配给Type
对象。 - 可使用
x:Array
标记扩展在 XAML 中定义数组。 该标记扩展具有一个名为Type
的必需特性,用于指示数组中的元素类型。
有关 XAML 标记扩展的详细信息,请参阅使用 XAML 标记扩展。
后续步骤
.NET MAUI 数据绑定支持将两个对象的属性链接在一起,这样一个对象发生更改会引起另一个对象也发生更改。