Xamarin.Forms 中的样式继承

样式可以从其他样式继承,以减少重复并实现重用。

XAML 中的样式继承

样式继承通过将 Style.BasedOn 属性设置为现有的 Style 来执行。 在 XAML 中,这通过将 BasedOn 属性设置为引用先前创建的 StyleStaticResource 标记扩展来实现。 在 C# 中,这通过将 BasedOn 属性设置为 Style 实例来实现。

从基本样式继承的样式可以包含新属性的 Setter 实例,或使用它们替代基本样式中的样式。 此外,从基准样式继承的样式必须面向同一类型,或者面向从基准样式所面向的类型派生的类型。 例如,如果基本样式面向 View 实例,则基于基本样式的样式可以面向从 View 类派生的 View 实例或类型,例如 LabelButton 实例。

以下代码演示 XAML 页面中的显式样式继承

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.StyleInheritancePage" Title="Inheritance" IconImageSource="xaml.png">
    <ContentPage.Resources>
        <ResourceDictionary>
            <Style x:Key="baseStyle" TargetType="View">
                <Setter Property="HorizontalOptions"
                        Value="Center" />
                <Setter Property="VerticalOptions"
                        Value="CenterAndExpand" />
            </Style>
            <Style x:Key="labelStyle" TargetType="Label"
                   BasedOn="{StaticResource baseStyle}">
                ...
                <Setter Property="TextColor" Value="Teal" />
            </Style>
            <Style x:Key="buttonStyle" TargetType="Button"
                   BasedOn="{StaticResource baseStyle}">
                <Setter Property="BorderColor" Value="Lime" />
                ...
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>
    <ContentPage.Content>
        <StackLayout Padding="0,20,0,0">
            <Label Text="These labels"
                   Style="{StaticResource labelStyle}" />
            ...
            <Button Text="So is the button"
                    Style="{StaticResource buttonStyle}" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

baseStyle 面向 View 实例,并设置 HorizontalOptionsVerticalOptions 属性。 不在任何控件上直接设置 baseStyle。 相反,labelStylebuttonStyle 从中继承,从而设置其他可绑定属性值。 然后,通过设置 Style 属性,将 labelStylebuttonStyle 应用于 Label 实例和 Button 实例。 这会导致如以下屏幕截图中所示的外观:

样式继承屏幕截图

注意

隐式样式可以派生自显式样式,但显式样式不能派生自隐式样式。

遵循继承链

样式只能从视图层次结构中相同级别或更高级别的样式继承。 这表示:

  • 应用程序级别的资源只能从其他应用程序级别的资源继承。
  • 页面级别的资源可以从应用程序级别的资源和其他页面级别的资源继承。
  • 控件级别的资源可以从应用程序级别的资源、页面级别的资源和其他控件级别的资源继承。

以下代码示例对此继承链进行了演示:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.StyleInheritancePage" Title="Inheritance" IconImageSource="xaml.png">
    <ContentPage.Resources>
        <ResourceDictionary>
            <Style x:Key="baseStyle" TargetType="View">
              ...
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>
    <ContentPage.Content>
        <StackLayout Padding="0,20,0,0">
            <StackLayout.Resources>
                <ResourceDictionary>
                    <Style x:Key="labelStyle" TargetType="Label" BasedOn="{StaticResource baseStyle}">
                      ...
                    </Style>
                    <Style x:Key="buttonStyle" TargetType="Button" BasedOn="{StaticResource baseStyle}">
                      ...
                    </Style>
                </ResourceDictionary>
            </StackLayout.Resources>
            ...
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

在此示例中,labelStylebuttonStyle 是控件级别的资源,而 baseStyle 是页面级别的资源。 但是,虽然 labelStylebuttonStyle 可以从 baseStyle 继承,但由于视图层次结构中各自的位置,baseStyle 无法从 labelStylebuttonStyle 继承。

C# 中的样式继承

以下代码示例显示了等效的 C# 页面,其中 Style 实例直接分配给所需控件的 Style 属性:

public class StyleInheritancePageCS : ContentPage
{
    public StyleInheritancePageCS ()
    {
        var baseStyle = new Style (typeof(View)) {
            Setters = {
                new Setter {
                    Property = View.HorizontalOptionsProperty, Value = LayoutOptions.Center    },
                ...
            }
        };

        var labelStyle = new Style (typeof(Label)) {
            BasedOn = baseStyle,
            Setters = {
                ...
                new Setter { Property = Label.TextColorProperty, Value = Color.Teal    }
            }
        };

        var buttonStyle = new Style (typeof(Button)) {
            BasedOn = baseStyle,
            Setters = {
                new Setter { Property = Button.BorderColorProperty, Value =    Color.Lime },
                ...
            }
        };
        ...

        Content = new StackLayout {
            Children = {
                new Label { Text = "These labels", Style = labelStyle },
                ...
                new Button { Text = "So is the button", Style = buttonStyle }
            }
        };
    }
}

baseStyle 面向 View 实例,并设置 HorizontalOptionsVerticalOptions 属性。 不在任何控件上直接设置 baseStyle。 相反,labelStylebuttonStyle 从中继承,从而设置其他可绑定属性值。 然后,通过设置 Style 属性,将 labelStylebuttonStyle 应用于 Label 实例和 Button 实例。