Herencia de estilos en Xamarin.Forms

Download SampleDescargar el ejemplo

Los estilos se pueden heredar de otros estilos para reducir la duplicación y habilitar la reutilización.

Herencia de estilos en XAML

La herencia de estilos se realiza mediante el establecimiento de la propiedad Style.BasedOn en un elemento Style existente. En XAML, esto se logra al establecer la propiedad BasedOn en una extensión de marcado StaticResource que hace referencia a una instancia de Style creada anteriormente. En C#, esto se logra al establecer la propiedad BasedOn en una instancia de Style.

Los estilos que heredan de un estilo base pueden incluir instancias Setter para nuevas propiedades o usarlos para invalidar estilos del estilo base. Además, los estilos que heredan de un estilo base deben tener como destino el mismo tipo o un tipo que derive del tipo destinado al estilo base. Por ejemplo, si un estilo base tiene como destino instancias de View, los estilos basados en el estilo base pueden tener como destino instancias de View o tipos que derivan de la clase View, como las instancias de Label y Button.

En el código siguiente se muestra la herencia de estilos explícita en una página 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 tiene como destino instancias de View y establece las propiedades HorizontalOptions y VerticalOptions. baseStyle no está establecido directamente en ningún control. En su lugar, labelStyle y buttonStyle heredan de él, estableciendo valores de propiedad enlazables adicionales. Después, labelStyle y buttonStyle se aplican a las instancias de Label y a la instancia de Button, mediante el establecimiento de sus propiedades Style. El resultado es el aspecto que se muestra en las capturas de pantalla siguientes:

Style inheritance screenshot

Nota:

Un estilo implícito se puede derivar de un estilo explícito, pero un estilo explícito no se puede derivar de un estilo implícito.

Respeto de la cadena de herencia

Un estilo solo puede heredar de estilos en el mismo nivel, o superior, en la jerarquía de la vista. Esto significa que:

  • Un recurso de nivel de aplicación solo puede heredar de otros recursos de nivel de aplicación.
  • Un recurso de nivel de página puede heredar de los recursos de nivel de aplicación y otros recursos de nivel de página.
  • Un recurso de nivel de control puede heredar de recursos de nivel de aplicación, recursos de nivel de página y otros recursos de nivel de control.

Esta cadena de herencia se muestra en el ejemplo de código siguiente:

<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>

En este ejemplo, labelStyle y buttonStyle son recursos de nivel de control, mientras que baseStyle es un recurso de nivel de página. Pero aunque labelStyle y buttonStyle heredan de baseStyle, baseStyle no puede heredar de labelStyle ni buttonStyle, debido a sus respectivas ubicaciones en la jerarquía de vistas.

Herencia de estilos en C#

En el ejemplo de código siguiente se muestra la página de C# equivalente, donde las instancias de Style se asignan directamente a las propiedades Style de los controles obligatorios:

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 tiene como destino instancias de View y establece las propiedades HorizontalOptions y VerticalOptions. baseStyle no está establecido directamente en ningún control. En su lugar, labelStyle y buttonStyle heredan de él, estableciendo valores de propiedad enlazables adicionales. Después, labelStyle y buttonStyle se aplican a las instancias de Label y a la instancia de Button, mediante el establecimiento de sus propiedades Style.