使用 XAML 标记扩展

Download Sample下载示例

XAML 标记扩展支持从各种源设置元素属性,从而帮助增强 XAML 的功能和灵活性。 多个 XAML 标记扩展是 XAML 2009 规范的一部分。 它们出现在 XAML 文件中,带有惯用的 x 命名空间前缀,并且通常用此前缀来进行引用。 本文讨论以下标记扩展:

  • x:Static - 引用静态属性、字段或枚举成员。
  • x:Reference - 引用页面上的命名元素。
  • x:Type - 将属性设置为 System.Type 对象。
  • x:Array - 构造特定类型的对象的数组。
  • x:Null - 将属性设置为值 null
  • OnPlatform - 基于每个平台自定义 UI 外观。
  • OnIdiom - 根据运行应用程序的设备的惯用法自定义 UI 外观。
  • DataTemplate- 将类型转换为 DataTemplate
  • FontImage - 在任何可以显示 ImageSource 的视图中显示字体图标。
  • AppThemeBinding - 根据当前系统主题使用资源。

其他 XAML 标记扩展历来受到其他 XAML 实现的支持,也受 Xamarin.Forms 的支持。 其他文章更全面地介绍了这些内容:

  • StaticResource - 引用资源字典中的对象,如资源字典一文中所述
  • DynamicResource - 响应资源字典中对象的更改,如动态样式一文中所述
  • Binding - 在两个对象的属性之间建立链接,如数据绑定一文中所述
  • TemplateBinding - 从控件模板执行数据绑定,如 Xamarin.Forms 控件模板一文中所述
  • RelativeSource - 设置相对于绑定目标位置的绑定源,如相对绑定一文中所述。

RelativeLayout 布局使用自定义标记扩展 ConstraintExpression。 此标记扩展在 RelativeLayout 一文中予以介绍

x:Static 标记扩展

StaticExtension 类支持 x:Static 标记扩展。 该类具有类型为 string 的名为 Member 的单一属性,你可以将其设置为公共常量、静态属性、静态字段或枚举成员的名称。

使用 x:Static 的一种常见方法是首先定义一个带有一些常量或静态变量的类,例如 MarkupExtensions 程序中的这个 AppConstants 小类

static class AppConstants
{
    public static double NormalFontSize = 18;
}

“x:Static 演示”页面展示了多种使用 x:Static 标记扩展的方法。 最详细的方法是实例化 Label.FontSize 属性元素标记之间的 StaticExtension 类:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:sys="clr-namespace:System;assembly=netstandard"
             xmlns:local="clr-namespace:MarkupExtensions"
             x:Class="MarkupExtensions.StaticDemoPage"
             Title="x:Static Demo">
    <StackLayout Margin="10, 0">
        <Label Text="Label No. 1">
            <Label.FontSize>
                <x:StaticExtension Member="local:AppConstants.NormalFontSize" />
            </Label.FontSize>
        </Label>

        ···

    </StackLayout>
</ContentPage>

XAML 分析程序还支持将 StaticExtension 类缩写为 x:Static

<Label Text="Label No. 2">
    <Label.FontSize>
        <x:Static Member="local:AppConstants.NormalFontSize" />
    </Label.FontSize>
</Label>

该方法可以进一步简化,但此更改会引入一些新语法:包括将 StaticExtension 类和成员设置放在大括号中。 生成的表达式直接设置为 FontSize 属性:

<Label Text="Label No. 3"
       FontSize="{x:StaticExtension Member=local:AppConstants.NormalFontSize}" />

请注意,在大括号中没有出现引号StaticExtensionMember 属性不再是 XML 特性, 而是标记扩展表达式的一部分。

正如将 x:StaticExtension 用作对象元素时可以将其缩写为 x:Static 一样,你也可以在大括号内的表达式中将其缩写:

<Label Text="Label No. 4"
       FontSize="{x:Static Member=local:AppConstants.NormalFontSize}" />

StaticExtension 类具有引用属性 MemberContentProperty 特性,该特性将此属性标记为该类的默认内容属性。 对于用大括号表示的 XAML 标记表达式,可以删除这类表达式的 Member= 部分:

<Label Text="Label No. 5"
       FontSize="{x:Static local:AppConstants.NormalFontSize}" />

这是 x:Static 标记扩展最常见的形式。

“静态演示”页包含另外两个示例。 XAML 文件的根标记包含 .NET System 命名空间的 XML 命名空间声明:

xmlns:sys="clr-namespace:System;assembly=netstandard"

这可以让 Label 字号设置为静态字段 Math.PI。 这会导致文本相当小,因此 Scale 属性设置为 Math.E

<Label Text="&#x03C0; &#x00D7; E sized text"
       FontSize="{x:Static sys:Math.PI}"
       Scale="{x:Static sys:Math.E}"
       HorizontalOptions="Center" />

最后一个示例显示 Device.RuntimePlatform 值。 Environment.NewLine 静态属性用于在两个 Span 对象之间插入一个新的换行符:

<Label HorizontalTextAlignment="Center"
       FontSize="{x:Static local:AppConstants.NormalFontSize}">
    <Label.FormattedText>
        <FormattedString>
            <Span Text="Runtime Platform: " />
            <Span Text="{x:Static sys:Environment.NewLine}" />
            <Span Text="{x:Static Device.RuntimePlatform}" />
        </FormattedString>
    </Label.FormattedText>
</Label>

下面是正在运行的示例:

x:Static Demo

x:Reference 标记扩展

ReferenceExtension 类支持 x:Reference 标记扩展。 该类具有 string 类型的名为 Name 的单一属性,可以将其设置为页面上已使用 x:Name 命名的元素的名称。 此 Name 属性是 ReferenceExtension 的内容属性,因此如果大括号中有 x:Reference,则不需要 Name=

x:Reference 标记扩展专用于数据绑定,数据绑定一文对此进行了更详细的介绍

“x:Reference 演示”页面显示了 x:Reference 在数据绑定中的两种用法,第一种是用于设置 Binding 对象的 Source 属性,第二种是用来设置两个数据绑定的 BindingContext 属性

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MarkupExtensions.ReferenceDemoPage"
             x:Name="page"
             Title="x:Reference Demo">

    <StackLayout Margin="10, 0">

        <Label Text="{Binding Source={x:Reference page},
                              StringFormat='The type of this page is {0}'}"
               FontSize="18"
               VerticalOptions="CenterAndExpand"
               HorizontalTextAlignment="Center" />

        <Slider x:Name="slider"
                Maximum="360"
                VerticalOptions="Center" />

        <Label BindingContext="{x:Reference slider}"
               Text="{Binding Value, StringFormat='{0:F0}&#x00B0; rotation'}"
               Rotation="{Binding Value}"
               FontSize="24"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />

    </StackLayout>
</ContentPage>

两个 x:Reference 表达式都使用 ReferenceExtension 类名的缩写版本,并消除了表达式的 Name= 部分。 在第一个示例中,x:Reference 标记扩展嵌入到 Binding 标记扩展中。 注意,SourceStringFormat 设置用逗号分隔。 下面是正在运行的程序:

x:Reference Demo

x:Type 标记扩展

x:Type 标记扩展是 C# typeof 关键字的 XAML 等效项。 它受 TypeExtension 类支持,该类定义了一个类型为 string 的名为 TypeName 的属性,该属性设置为类名或结构名。 x:Type 标记扩展返回该类或结构的 System.Type 对象。 TypeNameTypeExtension 的内容属性,因此 x:Type 与大括号一起出现时,不需要 TypeName=

在 Xamarin.Forms 中,有几个属性具有类型为 Type 的参数。 示例包括 StyleTargetType 属性,以及用于在泛型类中指定参数的 x:TypeArguments 属性。 但是,XAML 分析程序会自动执行 typeof 操作,在这些情况下不会使用 x:Type 标记扩展。

需要 x:Type 的地方是 x:Array 标记扩展,这将在下一节中介绍

x:Type 标记扩展在构造菜单时也很有用,在这种情况下,每个菜单项都对应特定类型的对象。 可以将 Type 对象与每个菜单项关联,然后在选中菜单项时实例化该对象。

这就是标记扩展程序中 MainPage 中的导航菜单的工作原理。 MainPage.xaml 文件包含 TableView,每个 TextCell 对应于程序中的特定页面

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MarkupExtensions"
             x:Class="MarkupExtensions.MainPage"
             Title="Markup Extensions"
             Padding="10">
    <TableView Intent="Menu">
        <TableRoot>
            <TableSection>
                <TextCell Text="x:Static Demo"
                          Detail="Access constants or statics"
                          Command="{Binding NavigateCommand}"
                          CommandParameter="{x:Type local:StaticDemoPage}" />

                <TextCell Text="x:Reference Demo"
                          Detail="Reference named elements on the page"
                          Command="{Binding NavigateCommand}"
                          CommandParameter="{x:Type local:ReferenceDemoPage}" />

                <TextCell Text="x:Type Demo"
                          Detail="Associate a Button with a Type"
                          Command="{Binding NavigateCommand}"
                          CommandParameter="{x:Type local:TypeDemoPage}" />

                <TextCell Text="x:Array Demo"
                          Detail="Use an array to fill a ListView"
                          Command="{Binding NavigateCommand}"
                          CommandParameter="{x:Type local:ArrayDemoPage}" />

                ···                          

        </TableRoot>
    </TableView>
</ContentPage>

下面是标记扩展中打开的主页

Main Page

每个 CommandParameter 属性都设置为引用其他页面之一的 x:Type 标记扩展。 每个 Command 属性都绑定到一个名为 NavigateCommand 的属性。 此属性在 MainPage 代码隐藏文件中定义:

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();

        NavigateCommand = new Command<Type>(async (Type pageType) =>
        {
            Page page = (Page)Activator.CreateInstance(pageType);
            await Navigation.PushAsync(page);
        });

        BindingContext = this;
    }

    public ICommand NavigateCommand { private set; get; }
}

NavigateCommand 属性是一个 Command 对象,它使用类型为 Type 的参数(CommandParameter 的值)实现执行命令。 该方法使用 Activator.CreateInstance 实例化页面,然后导航到该页。 构造函数最后将页面的 BindingContext 设置为自身,使得 Command 上的 Binding 可以正常工作。 请参阅数据绑定一文,特别是命令文章,了解有关此类代码的更多详细信息

“x:Type 演示”页面使用类似的技术实例化 Xamarin.Forms 元素并将它们添加到 StackLayout。 XAML 文件最初由三个 Button 元素组成,它们的 Command 属性设置为 BindingCommandParameter 属性设置为三个 Xamarin.Forms 视图的类型:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MarkupExtensions.TypeDemoPage"
             Title="x:Type Demo">

    <StackLayout x:Name="stackLayout"
                 Padding="10, 0">

        <Button Text="Create a Slider"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand"
                Command="{Binding CreateCommand}"
                CommandParameter="{x:Type Slider}" />

        <Button Text="Create a Stepper"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand"
                Command="{Binding CreateCommand}"
                CommandParameter="{x:Type Stepper}" />

        <Button Text="Create a Switch"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand"
                Command="{Binding CreateCommand}"
                CommandParameter="{x:Type Switch}" />
    </StackLayout>
</ContentPage>

代码隐藏文件定义并初始化 CreateCommand 属性:

public partial class TypeDemoPage : ContentPage
{
    public TypeDemoPage()
    {
        InitializeComponent();

        CreateCommand = new Command<Type>((Type viewType) =>
        {
            View view = (View)Activator.CreateInstance(viewType);
            view.VerticalOptions = LayoutOptions.CenterAndExpand;
            stackLayout.Children.Add(view);
        });

        BindingContext = this;
    }

    public ICommand CreateCommand { private set; get; }
}

在按下 Button 时执行的方法会创建参数的新实例,设置其 VerticalOptions 属性,并将其添加到 StackLayout 中。 然后,这三个 Button 元素与动态创建的视图共享页面:

x:Type Demo

x:Array 标记扩展

通过 x:Array 标记扩展,可以在标记中定义数组。 ArrayExtension 类对其提供支持,该类定义两个属性:

  • Type 类型的 Type,表示数组中元素的类型。
  • IList 类型的 Items,它是项本身的集合。 这是 ArrayExtension 的内容属性。

x:Array 标记扩展本身不会出现在大括号中。 但 x:Array 的开始标记和结束标记会分隔项列表。 将 Type 属性设置为 x:Type 标记扩展。

“x:Array 演示”页面显示了如何通过设置数组的 ItemsSource 属性来使用 x:ArrayListView 添加项

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MarkupExtensions.ArrayDemoPage"
             Title="x:Array Demo Page">
    <ListView Margin="10">
        <ListView.ItemsSource>
            <x:Array Type="{x:Type Color}">
                <Color>Aqua</Color>
                <Color>Black</Color>
                <Color>Blue</Color>
                <Color>Fuchsia</Color>
                <Color>Gray</Color>
                <Color>Green</Color>
                <Color>Lime</Color>
                <Color>Maroon</Color>
                <Color>Navy</Color>
                <Color>Olive</Color>
                <Color>Pink</Color>
                <Color>Purple</Color>
                <Color>Red</Color>
                <Color>Silver</Color>
                <Color>Teal</Color>
                <Color>White</Color>
                <Color>Yellow</Color>
            </x:Array>
        </ListView.ItemsSource>

        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <BoxView Color="{Binding}"
                             Margin="3" />    
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</ContentPage>        

ViewCell 为每个颜色条目创建一个简单的 BoxView

x:Array Demo

可通过多种方式指定此数组中的单个 Color 项。 可以使用 x:Static 标记扩展:

<x:Static Member="Color.Blue" />

或者,可使用 StaticResource 从资源字典中检索颜色:

<StaticResource Key="myColor" />

本文结束时,你将看到一个自定义 XAML 标记扩展,该扩展还会创建新的颜色值:

<local:HslColor H="0.5" S="1.0" L="0.5" />

定义常见类型的数组(如字符串或数字)时,请使用传递构造函数参数一文中列出的标记来分隔值

x:Null 标记扩展

NullExtension 类支持 x:Null 标记扩展。 它没有属性,只是 C# null 关键字的 XAML 等效项。

x:Null 标记扩展很少需要,也很少使用,但如果确实需要它,你会庆幸有它。

“x:Null 演示”页面展示了一个场景,在该场景中 x:Null 可能很方便。 假设你为 Label 定义了一个隐式 Style,其中包含一个 Setter,它将 FontFamily 属性设置为与平台相关的系列名称:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MarkupExtensions.NullDemoPage"
             Title="x:Null Demo">
    <ContentPage.Resources>
        <ResourceDictionary>
            <Style TargetType="Label">
                <Setter Property="FontSize" Value="48" />
                <Setter Property="FontFamily">
                    <Setter.Value>
                        <OnPlatform x:TypeArguments="x:String">
                            <On Platform="iOS" Value="Times New Roman" />
                            <On Platform="Android" Value="serif" />
                            <On Platform="UWP" Value="Times New Roman" />
                        </OnPlatform>
                    </Setter.Value>
                </Setter>
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>

    <ContentPage.Content>
        <StackLayout Padding="10, 0">
            <Label Text="Text 1" />
            <Label Text="Text 2" />

            <Label Text="Text 3"
                   FontFamily="{x:Null}" />

            <Label Text="Text 4" />
            <Label Text="Text 5" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>   

然后你发现,对于其中一个 Label 元素,需要使用隐式 Style 中的所有属性设置,但 FontFamily 除外,你需要将其设置为默认值。 为此,可以另外定义一个 Style,但更简单的方法是将特定 LabelFontFamily 属性设置为 x:Null,如中间的 Label 所示。

下面是正在运行的程序:

x:Null Demo

注意,其中四个 Label 元素采用 serif 字体,但中间的 Label 元素采用默认的 sans-serif 字体。

OnPlatform 标记扩展

OnPlatform 标记扩展使你能够基于平台自定义 UI 外观。 它提供的功能与 OnPlatformOn 类相同,但表现形式更简洁。

OnPlatform 标记扩展由 OnPlatformExtension 类提供支持,该类定义以下属性:

  • object 类型的 Default,设置为默认值,以应用于表示平台的属性。
  • object 类型的 Android,设置为在 Android 上应用的值。
  • 类型为 objectGTK,设置为要在 GTK 平台上应用的值。
  • object 类型为 iOS,设置为在 iOS 上应用的值。
  • 类型为 objectmacOS,设置为要在 macOS 上应用的值。
  • object 类型的 Tizen,设置为在 Tizen 平台上应用的值。
  • 类型为 objectUWP,设置为要在通用 Windows 平台上应用的值。
  • 类型为 objectWPF,设置为要在 Windows Presentation Foundation 平台上应用的值。
  • IValueConverter 类型的 Converter,可设置为 IValueConverter 实现。
  • object 类型的 ConverterParameter,可设置为传递给 IValueConverter 实现的值。

注意

XAML 分析程序允许将 OnPlatformExtension 类缩写为 OnPlatform

Default 属性是 OnPlatformExtension 的内容属性。 因此,对于用大括号表示的 XAML 标记表达式,可以删除此类表达式的 Default= 部分(前提是它是第一个参数)。 如果未设置 Default 属性,则默认为 BindableProperty.DefaultValue 属性值,前提是标记扩展名的目标是 BindableProperty

重要说明

XAML 分析程序要求将正确类型的值提供给使用 OnPlatform 标记扩展的属性。 如果需要类型转换,OnPlatform 标记扩展将尝试使用 Xamarin.Forms 提供的默认转换器执行该转换。 但是,某些类型转换不能由默认转换器执行,在这些情况下,Converter 属性应设置为 IValueConverter 实现。

OnPlatform Demo 页显示如何使用 OnPlatform 标记扩展:

<BoxView Color="{OnPlatform Yellow, iOS=Red, Android=Green, UWP=Blue}"
         WidthRequest="{OnPlatform 250, iOS=200, Android=300, UWP=400}"  
         HeightRequest="{OnPlatform 250, iOS=200, Android=300, UWP=400}"
         HorizontalOptions="Center" />

在此示例中,所有三个 OnPlatform 表达式都使用 OnPlatformExtension 类名的简化版本。 三个 OnPlatform 标记扩展针对 iOS、Android 和 UWP 将 BoxViewColorWidthRequestHeightRequest 属性设置不同的值。 标记扩展还为未指定平台上的这些属性提供默认值,同时删除表达式的 Default= 部分。 请注意,设置的标记扩展属性用逗号分隔。

下面是正在运行的程序:

OnPlatform Demo

OnIdiom 标记扩展

通过 OnIdiom 标记扩展,可以根据运行应用程序的设备的惯用法来自定义 UI 外观。 它受定义以下属性的 OnIdiomExtension 类支持:

  • object 类型的 Default,设置为要应用于表示设备风格的属性的默认值。
  • object 类型的 Phone,设置为要在手机上应用的值。
  • object 类型的 Tablet,设置为要在平板电脑上应用的值。
  • object 类型的 Desktop,设置为要在桌面平台上应用的值。
  • object 类型的 TV,设置为要在电视平台上应用的值。
  • object 类型的 Watch,设置为要在 Watch 平台上应用的值。
  • IValueConverter 类型的 Converter,可设置为 IValueConverter 实现。
  • object 类型的 ConverterParameter,可设置为传递给 IValueConverter 实现的值。

注意

XAML 分析程序允许将 OnIdiomExtension 类缩写为 OnIdiom

Default 属性是 OnIdiomExtension 的内容属性。 因此,对于用大括号表示的 XAML 标记表达式,可以删除此类表达式的 Default= 部分(前提是它是第一个参数)。

重要说明

XAML 分析程序要求将正确类型的值提供给使用 OnIdiom 标记扩展的属性。 如果需要类型转换,OnIdiom 标记扩展将尝试使用 Xamarin.Forms 提供的默认转换器执行该转换。 但是,某些类型转换不能由默认转换器执行,在这些情况下,Converter 属性应设置为 IValueConverter 实现。

“OnIdiom 演示”页面显示了如何使用 OnIdiom 标记扩展

<BoxView Color="{OnIdiom Yellow, Phone=Red, Tablet=Green, Desktop=Blue}"
         WidthRequest="{OnIdiom 100, Phone=200, Tablet=300, Desktop=400}"
         HeightRequest="{OnIdiom 100, Phone=200, Tablet=300, Desktop=400}"
         HorizontalOptions="Center" />

在此示例中,所有三个 OnIdiom 表达式都使用 OnIdiomExtension 类名的简化版本。 这三个 OnIdiom 标记扩展会在手机、平板电脑和桌面惯例中将 BoxViewColorWidthRequestHeightRequest 属性设置为不同的值。 标记扩展还为未指定惯例中的这些属性提供默认值,同时删除表达式的 Default= 部分。 请注意,设置的标记扩展属性用逗号分隔。

下面是正在运行的程序:

OnIdiom Demo

DataTemplate 标记扩展

通过 DataTemplate 标记扩展,可以将类型转换为 DataTemplateDataTemplateExtension 类支持该标记扩展,该类定义了 string 类型的 TypeName 属性,该属性设置为要转换为 DataTemplate 的类型的名称。 TypeName 属性是 DataTemplateExtension 的内容属性。 因此,对于用大括号表示的 XAML 标记表达式,可以去掉这类表达式的 TypeName= 部分。

注意

XAML 分析程序允许将 DataTemplateExtension 类缩写为 DataTemplate

Shell 应用程序中提供了此标记扩展的常见用法,如以下示例所示:

<ShellContent Title="Monkeys"
              Icon="monkey.png"
              ContentTemplate="{DataTemplate views:MonkeysPage}" />

在此示例中,MonkeysPageContentPage 转换为 DataTemplate,并将其设置为 ShellContent.ContentTemplate 属性的值。 这可确保仅在导航到页面时创建 MonkeysPage,而不是在应用程序启动时创建。

有关 Shell 应用程序的详细信息,请参阅 Xamarin.Forms Shell

FontImage 标记扩展

FontImage 标记扩展支持在任何可以显示 ImageSource 的视图中显示字体图标。 它提供与 FontImageSource 类相同的功能,但具有更简洁的表示形式。

FontImage 标记扩展由 FontImageExtension 类提供支持,该类定义以下属性:

  • FontFamily,类型为 string,是字体图标所属的字体系列。
  • Glyph,类型为 string,是字体图标的 unicode 字符值。
  • Color,类型为 Color,是显示字体图标时要使用的颜色。
  • Size,类型为 double,是呈现字体图标的大小(使用设备无关单位)。 默认值为 30。 此外,可以将此属性设置为命名字体大小。

注意

XAML 分析程序允许将 FontImageExtension 类缩写为 FontImage

Glyph 属性是 FontImageExtension 的内容属性。 因此,对于用大括号表示的 XAML 标记表达式,可以删除此类表达式的 Glyph= 部分(前提是它是第一个参数)。

“FontImage 演示”页面显示了如何使用 FontImage 标记扩展

<Image BackgroundColor="#D1D1D1"
       Source="{FontImage &#xf30c;, FontFamily={OnPlatform iOS=Ionicons, Android=ionicons.ttf#}, Size=44}" />

在本例中,FontImageExtension 类名的缩写版本用于在 Image 中显示来自 Ionicons 字体系列的 XBox 图标。 表达式还使用 OnPlatform 标记扩展在 iOS 和 Android 上指定不同的 FontFamily 属性值。 此外,表达式的 Glyph= 部分会被消除,设置的标记扩展属性用逗号分隔。 注意,虽然图标的 unicode 字符是 \uf30c,但它必须在 XAML 中转义,因此变为 &#xf30c;

下面是正在运行的程序:

Screenshot of the FontImage markup extension

有关通过在 FontImageSource 对象中指定字体图标数据来显示字体图标的信息,请参阅显示字体图标

AppThemeBinding 标记扩展

AppThemeBinding 标记扩展使你能够根据当前系统主题指定要使用的资源,例如图像或颜色。

重要

AppThemeBinding 标记扩展具有最低操作系统要求。 有关详细信息,请参见响应 Xamarin.Forms 应用程序中的系统主题更改

AppThemeBinding 标记扩展由 AppThemeBindingExtension 类提供支持,该类定义以下属性:

  • Default,类型为 object,用户所设置的默认使用的资源。
  • Light,类型为 object,用户所设置的在设备使用其浅色主题时要使用的资源。
  • Dark,类型为 object,用户所设置的在设备使用其深色主题时要使用的资源。
  • Value,类型为 object,可返回标记扩展当前使用的资源。

注意

XAML 分析程序允许将 AppThemeBindingExtension 类缩写为 AppBindingTheme

Default 属性是 AppThemeBindingExtension 的内容属性。 因此,对于用大括号表示的 XAML 标记表达式,可以删除此类表达式的 Default= 部分(前提是它是第一个参数)。

“AppThemeBinding 演示”页面显示了如何使用 AppThemeBinding 标记扩展

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MarkupExtensions.AppThemeBindingDemoPage"
             Title="AppThemeBinding Demo">
    <ContentPage.Resources>

        <Style x:Key="labelStyle"
               TargetType="Label">
            <Setter Property="TextColor"
                    Value="{AppThemeBinding Black, Light=Blue, Dark=Teal}" />
        </Style>

    </ContentPage.Resources>
    <StackLayout Margin="20">
        <Label Text="This text is green in light mode, and red in dark mode."
               TextColor="{AppThemeBinding Light=Green, Dark=Red}" />
        <Label Text="This text is black by default, blue in light mode, and teal in dark mode."
               Style="{StaticResource labelStyle}" />
    </StackLayout>
</ContentPage>

在此示例中,当设备使用其浅色主题时,Label 的文本颜色被设置为绿色,当设备使用其深色主题时,文本颜色被设置为红色。 第二个 Label 通过 Style 设置其 TextColor 属性。 默认情况下,此 StyleLabel 的文本颜色设置为黑色,当设备使用浅色主题时设置为蓝色,在设备使用深色主题时设置为青色。

下面是正在运行的程序:

AppThemeBinding Demo

定义标记扩展

如果需要的 XAML 标记扩展在 Xamarin.Forms 中不可用,则可以创建自己的标记扩展