XAML 标记扩展
大部分的 XAML 定义会在编译时确定。 你通常知道应将元素定位到何处、将使用哪些颜色和字体,以及应将哪些文本值分配给属性。
但是,有时你需要将属性值设置为在编译时无法确定的值。 这些值只有在程序运行时才能知晓。 在这些情况下,可以创建一个对象,该对象在运行时为 XAML 提供值。 XAML 支持使用标记扩展实现此目的。
在本单元中,你将了解如何创建和使用标记扩展。
什么是标记扩展?
标记扩展是 XAML 中用于访问运行时值的类。 假设 XAML UI 中定义了多个标签,并且你要在整个应用中将 FontSize
属性设置为相同的值,以确保所有标签样式一致。 可以使用 XAML 设置 FontSize
属性,如以下示例所示:
<Label Text="Hello, World!"
Grid.Row="0"
SemanticProperties.HeadingLevel="Level1"
FontSize="28"
HorizontalOptions="CenterAndExpand"/>
可以为每个标签重复使用此相同设置,但如果以后想要更改此值,该怎么办? 需要找到此属性的每个实例并进行更改。 此外,假设你不知道要使用什么值,可以在运行时基于设备方向、屏幕分辨率或其他注意事项等因素来计算。 在这些情况下,你需要比硬编码文本更复杂的内容。 因此,标记扩展非常有用。 标记扩展使获取 XAML 中使用的值的方式变得灵活。
创建标记扩展
标记扩展是用于实现 Microsoft.Maui.Controls.Xaml.IMarkupExtension 接口的类。 此接口使用以下签名定义一个名为 ProvideValue
的方法:
public object ProvideValue(IServiceProvider serviceProvider)
{
...
}
此方法的目的是为 XAML 标记提供值。 请注意,返回类型为 object
,因此只要值适合使用该值的位置,该值就可以为任何类型。 例如,在计算和返回字号的标记扩展中,返回类型应为 double
。
serviceProvider
参数包含有关在 XAML 代码中使用标记扩展的位置的上下文信息;在其他信息中,它用于标识要向其应用扩展的控件。
FontSize
属性的标记扩展可以保持简单。 在下面的示例中,MainPage
类公开名为 MyFontSize
的 double
字段。 GlobalFontSizeExtension
类实现 IMarkupExtension
接口,并且 ProvideValue
方法返回 MyFontSize
变量的值:
namespace MyMauiApp;
public partial class MainPage : ContentPage
{
public const double MyFontSize = 28;
public MainPage()
{
InitializeComponent();
...
}
...
}
public class GlobalFontSizeExtension : IMarkupExtension
{
public object ProvideValue(IServiceProvider serviceProvider)
{
return MainPage.MyFontSize;
}
}
注意
MyFontSize
字段必须是 MainPage
类的 static
成员,才能以这种方式在 ProvideValue
方法中引用它。 好的做法意味着在这种情况下,变量也应该是常量。 值 const
为 static
。
ProvideValue
方法还可以根据方向和设备外形规格对返回的值进行调整。
将标记扩展应用于 XAML 中的控件
若要在 XAML 代码中使用标记扩展,请将包含 GlobalFontSizeExtension
类的命名空间添加到 ContentPage
标记中的命名空间列表。 在以下示例中,为此命名空间提供了别名 mycode:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:mycode="clr-namespace:MyMauiApp"
x:Class="MyMauiApp.MainPage">
可以使用标记扩展设置 FontSize
属性,如下所示。 请注意,按照约定,标记扩展的名称中包含后缀“Extension”。 XAML 可识别此后缀,在从 XAML 代码调用扩展时无需包含它。 在以下示例中,GlobalFontSizeExtension
类仅引用为 GlobalFontSize
:
<Label Text="Hello, World!"
Grid.Row="0"
SemanticProperties.HeadingLevel="Level1"
FontSize="{mycode:GlobalFontSize}"
HorizontalOptions="CenterAndExpand"/>
对于需要指定字号的任何控件,可以在整个 XAML 代码中应用相同的标记扩展。 以后如果决定更改字号,只需修改 MainPage
类中 MyFontSize
变量的定义。
StaticExtension 类
与 GlobalFontSize
标记扩展一样有用,但你不太可能创建此类扩展。 原因很简单;.NET MAUI 已经提供了更通用的扩展,可用于引用代码中的任何静态值。 此扩展命名为 StaticExtension
,简称 Static
。 以下代码显示了此扩展类的基本大纲:
[ContentProperty ("Member")]
public class StaticExtension : IMarkupExtension
{
public string Member {get; set;}
public object ProvideValue (IServiceProvider serviceProvider)
{
...
}
}
注意
自定义标记扩展的目的是允许你处理更复杂的情况,而不是简单的静态情况。 例如,可能需要基于设备外形规格动态地更改字号。
若要在 XAML 代码中使用此类,请提供要在 Member
属性中引用的静态变量的名称,ProvideValue
方法会在此变量中返回值。 下面的示例演示了如何使用该类:
<Label Text="Hello, World!"
Grid.Row="0"
SemanticProperties.HeadingLevel="Level1"
FontSize="{x:Static Member=mycode:MainPage.MyFontSize}"
HorizontalOptions="CenterAndExpand"/>
.NET MAUI 提供一组其他标记扩展类,可用于数据绑定、引用动态资源和样式以及处理数据数组等方案。