可以通过样式来自定义视觉对象元素的外观。 样式针对特定类型进行定义,它包含该类型上可用属性的值。
Xamarin.Forms 应用程序通常包含多个具有相同外观的控件。 例如,应用程序可能有多个具有相同字体选项和布局选项的 Label 实例,如以下 XAML 代码示例所示:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Class="Styles.NoStylesPage"
    Title="No Styles"
    IconImageSource="xaml.png">
    <ContentPage.Content>
        <StackLayout Padding="0,20,0,0">
            <Label Text="These labels"
                   HorizontalOptions="Center"
                   VerticalOptions="CenterAndExpand"
                   FontSize="Large" />
            <Label Text="are not"
                   HorizontalOptions="Center"
                   VerticalOptions="CenterAndExpand"
                   FontSize="Large" />
            <Label Text="using styles"
                   HorizontalOptions="Center"
                   VerticalOptions="CenterAndExpand"
                   FontSize="Large" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>
以下代码示例演示了在 C# 中创建的等效页:
public class NoStylesPageCS : ContentPage
{
    public NoStylesPageCS ()
    {
        Title = "No Styles";
        IconImageSource = "csharp.png";
        Padding = new Thickness (0, 20, 0, 0);
        Content = new StackLayout {
            Children = {
                new Label {
                    Text = "These labels",
                    HorizontalOptions = LayoutOptions.Center,
                    VerticalOptions = LayoutOptions.CenterAndExpand,
                    FontSize = Device.GetNamedSize (NamedSize.Large, typeof(Label))
                },
                new Label {
                    Text = "are not",
                    HorizontalOptions = LayoutOptions.Center,
                    VerticalOptions = LayoutOptions.CenterAndExpand,
                    FontSize = Device.GetNamedSize (NamedSize.Large, typeof(Label))
                },
                new Label {
                    Text = "using styles",
                    HorizontalOptions = LayoutOptions.Center,
                    VerticalOptions = LayoutOptions.CenterAndExpand,
                    FontSize = Device.GetNamedSize (NamedSize.Large, typeof(Label))
                }
            }
        };
    }
}
每个 Label 实例都有相同的属性值,用于控制通过 Label 显示的文本的外观。 这会导致如以下屏幕截图中所示的外观:
设置每个单独控件的外观可能是重复性的操作,容易出错。 相反,可以创建用于定义外观的样式,然后将其应用于所需控件。
创建样式
Style 类将属性值的集合分组到一个对象中,然后可以将该对象应用于多个视觉对象元素实例。 这有助于减少重复标记,可以更轻松地更改应用程序的外观。
尽管样式主要是为基于 XAML 的应用程序设计的,但它们也可以在 C# 中创建:
- 在 XAML 中创建的 Style实例通常在分配给控件、页面的Resources集合或应用程序的Resources集合的ResourceDictionary中定义。
- 在 C# 中创建的 Style实例通常在页面的类中定义,或者在可以进行全局访问的类中定义。
选择在何处定义 Style 会影响其应用范围:
每个 Style 实例都包含一个或多个 Setter 对象的集合,其中每个 Setter 都具有 Property 和 Value。 Property 是应用样式的元素的可绑定属性的名称,而 Value 是应用于属性的值。
每个 Style 实例都可以是显式的或隐式的:
- 通过指定值TargetType和x:Key值以及将目标元素Style的属性设置为x:Key引用来定义显式Style实例。 有关显式样式的详细信息,请参阅显式样式。
- 通过仅指定一个TargetType隐式实例来定义隐式Style实例。Style实例随后将自动应用于该类型的所有元素。 请注意,TargetType的子类不会自动应用Style。 有关隐式样式的详细信息,请参阅隐式样式。
创建 Style 时,始终需要 TargetType 属性。 以下代码示例显示了在 XAML 中创建的显式样式(请注意 x:Key):
<Style x:Key="labelStyle" TargetType="Label">
    <Setter Property="HorizontalOptions" Value="Center" />
    <Setter Property="VerticalOptions" Value="CenterAndExpand" />
    <Setter Property="FontSize" Value="Large" />
</Style>
若要应用 Style,目标对象必须是与 Style 的 TargetType 属性值匹配的 VisualElement,如以下 XAML 代码示例所示:
<Label Text="Demonstrating an explicit style" Style="{StaticResource labelStyle}" />
视图层次结构中等级较低的样式优先于定义为较高等级的样式。 例如,在应用程序级别设置一个将 Label.TextColor 设置为 Red 的 Style 时,该操作会被将 Label.TextColor 设置为 Green 的页面级别样式覆盖。 同样,页面级别样式会被控件级别样式覆盖。 此外,如果直接在控件属性上设置 Label.TextColor,则其优先于任何样式。
本部分的文章演示并解释了如何创建和应用显式和隐式样式、如何创建全局样式、样式继承、如何在运行时响应样式更改,以及如何使用 Xamarin.Forms 中包含的内置样式。
注意
什么是 StyleId?
在 Xamarin.Forms 2.2 之前,StyleId 属性用于识别应用程序中的各个元素,以便在 UI 测试和主题引擎(例如 Pixate)中进行识别。 不过,Xamarin.Forms 2.2 引入了 AutomationId 属性,它取代了 StyleId 属性。
