Estilos dinámicos en Xamarin.Forms

Los estilos no responden a los cambios de propiedad y permanecen sin cambios durante la duración de una aplicación. Por ejemplo, después de asignar un estilo a un elemento visual, si se modifica o se quita cualquiera de las instancias de Setter, o se agrega una instancia nueva de Setter, los cambios no se aplicarán a este elemento. Sin embargo, las aplicaciones pueden responder a los cambios de estilo dinámicamente en tiempo de ejecución mediante recursos dinámicos.

La extensión de marcado DynamicResource es similar a la extensión de marcado StaticResource en que ambos usan una clave de diccionario para capturar un valor de ResourceDictionary. Pero mientras StaticResource realiza una búsqueda de diccionario única, DynamicResource mantiene un vínculo a la clave del diccionario. Por lo tanto, si se reemplaza la entrada del diccionario asociada a la clave, el cambio se aplica al elemento visual. Esto permite realizar cambios de estilo en tiempo de ejecución en una aplicación.

En el código de ejemplo siguiente se muestran estilos dinámicos 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.DynamicStylesPage" Title="Dynamic" IconImageSource="xaml.png">
    <ContentPage.Resources>
        <ResourceDictionary>
            <Style x:Key="baseStyle" TargetType="View">
              ...
            </Style>
            <Style x:Key="blueSearchBarStyle"
                   TargetType="SearchBar"
                   BasedOn="{StaticResource baseStyle}">
              ...
            </Style>
            <Style x:Key="greenSearchBarStyle"
                   TargetType="SearchBar">
              ...
            </Style>
            ...
        </ResourceDictionary>
    </ContentPage.Resources>
    <ContentPage.Content>
        <StackLayout Padding="0,20,0,0">
            <SearchBar Placeholder="These SearchBar controls"
                       Style="{DynamicResource searchBarStyle}" />
            ...
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

Las instancias de SearchBar usan la extensión de marcado DynamicResource para hacer referencia a un elemento de Style denominado searchBarStyle, que no está definido en el XAML. Sin embargo, dado que las propiedades de Style de las instancias de SearchBar se establecen mediante DynamicResource, la clave de diccionario que falta no genera una excepción.

En su lugar, en el archivo de código subyacente, el constructor crea una entrada de ResourceDictionary con la clave searchBarStyle, como se muestra en el código de ejemplo siguiente:

public partial class DynamicStylesPage : ContentPage
{
    bool originalStyle = true;

    public DynamicStylesPage ()
    {
        InitializeComponent ();
        Resources ["searchBarStyle"] = Resources ["blueSearchBarStyle"];
    }

    void OnButtonClicked (object sender, EventArgs e)
    {
        if (originalStyle) {
            Resources ["searchBarStyle"] = Resources ["greenSearchBarStyle"];
            originalStyle = false;
        } else {
            Resources ["searchBarStyle"] = Resources ["blueSearchBarStyle"];
            originalStyle = true;
        }
    }
}

Cuando se ejecute el controlador de eventos OnButtonClicked, searchBarStyle cambiará entre blueSearchBarStyle y greenSearchBarStyle. El resultado es el aspecto que se muestra en las capturas de pantalla siguientes:

Ejemplo de estilo dinámico azulEjemplo de estilo dinámico verde

En el ejemplo de código siguiente se muestra la página equivalente en C#:

public class DynamicStylesPageCS : ContentPage
{
    bool originalStyle = true;

    public DynamicStylesPageCS ()
    {
        ...
        var baseStyle = new Style (typeof(View)) {
            ...
        };
        var blueSearchBarStyle = new Style (typeof(SearchBar)) {
            ...
        };
        var greenSearchBarStyle = new Style (typeof(SearchBar)) {
            ...
        };
        ...
        var searchBar1 = new SearchBar { Placeholder = "These SearchBar controls" };
        searchBar1.SetDynamicResource (VisualElement.StyleProperty, "searchBarStyle");
        ...
        Resources = new ResourceDictionary ();
        Resources.Add ("blueSearchBarStyle", blueSearchBarStyle);
        Resources.Add ("greenSearchBarStyle", greenSearchBarStyle);
        Resources ["searchBarStyle"] = Resources ["blueSearchBarStyle"];

        Content = new StackLayout {
            Children = { searchBar1, searchBar2, searchBar3, searchBar4,    button    }
        };
    }
    ...
}

En C#, las instancias de SearchBar usan el método SetDynamicResource para hacer referencia a searchBarStyle. El código del controlador de eventos OnButtonClicked es idéntico al ejemplo XAML y, cuando se ejecuta, searchBarStyle cambiará entre blueSearchBarStyle y greenSearchBarStyle.

Herencia de estilo dinámico

La derivación de estilo de un estilo dinámico no se puede lograr mediante la propiedad Style.BasedOn. En su lugar, la clase Style incluye la propiedad BaseResourceKey, que se puede establecer en una clave de diccionario cuyo valor podría cambiar de manera dinámica.

En el código de ejemplo siguiente se muestra la herencia del estilo dinámico 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.DynamicStylesInheritancePage" Title="Dynamic Inheritance" IconImageSource="xaml.png">
    <ContentPage.Resources>
        <ResourceDictionary>
            <Style x:Key="baseStyle" TargetType="View">
              ...
            </Style>
            <Style x:Key="blueSearchBarStyle" TargetType="SearchBar" BasedOn="{StaticResource baseStyle}">
              ...
            </Style>
            <Style x:Key="greenSearchBarStyle" TargetType="SearchBar">
              ...
            </Style>
            <Style x:Key="tealSearchBarStyle" TargetType="SearchBar" BaseResourceKey="searchBarStyle">
              ...
            </Style>
            ...
        </ResourceDictionary>
    </ContentPage.Resources>
    <ContentPage.Content>
        <StackLayout Padding="0,20,0,0">
            <SearchBar Text="These SearchBar controls" Style="{StaticResource tealSearchBarStyle}" />
            ...
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

Las instancias de SearchBar usan la extensión de marcado StaticResource para hacer referencia a un objeto Style denominado tealSearchBarStyle. Style establece algunas propiedades adicionales y usa la propiedad BaseResourceKey para hacer referencia a searchBarStyle. La extensión de marcado DynamicResource no es necesaria porque tealSearchBarStyle no cambiará, a excepción de Style, del que deriva. Por lo tanto, tealSearchBarStyle mantiene un vínculo a searchBarStyle y se modifica cuando cambia el estilo base.

En el archivo de código subyacente, el constructor crea una entrada de ResourceDictionary con la clave searchBarStyle, según el ejemplo anterior que mostró estilos dinámicos. Cuando se ejecute el controlador de eventos OnButtonClicked, searchBarStyle cambiará entre blueSearchBarStyle y greenSearchBarStyle. El resultado es el aspecto que se muestra en las capturas de pantalla siguientes:

Ejemplo de herencia de estilo dinámico azulEjemplo de herencia de estilo dinámico verde

En el ejemplo de código siguiente se muestra la página equivalente en C#:

public class DynamicStylesInheritancePageCS : ContentPage
{
    bool originalStyle = true;

    public DynamicStylesInheritancePageCS ()
    {
        ...
        var baseStyle = new Style (typeof(View)) {
            ...
        };
        var blueSearchBarStyle = new Style (typeof(SearchBar)) {
            ...
        };
        var greenSearchBarStyle = new Style (typeof(SearchBar)) {
            ...
        };
        var tealSearchBarStyle = new Style (typeof(SearchBar)) {
            BaseResourceKey = "searchBarStyle",
            ...
        };
        ...
        Resources = new ResourceDictionary ();
        Resources.Add ("blueSearchBarStyle", blueSearchBarStyle);
        Resources.Add ("greenSearchBarStyle", greenSearchBarStyle);
        Resources ["searchBarStyle"] = Resources ["blueSearchBarStyle"];

        Content = new StackLayout {
            Children = {
                new SearchBar { Text = "These SearchBar controls", Style = tealSearchBarStyle },
                ...
            }
        };
    }
    ...
}

tealSearchBarStyle se asigna directamente a la propiedad Style de las instancias de SearchBar. Este elemento Style establece algunas propiedades adicionales y usa la propiedad BaseResourceKey para hacer referencia a searchBarStyle. El método SetDynamicResource no es necesario aquí porque tealSearchBarStyle no cambiará, excepto el Style del que deriva. Por lo tanto, tealSearchBarStyle mantiene un vínculo a searchBarStyle y se modifica cuando cambia el estilo base.

Encuentre más vídeos de Xamarin en Channel 9 y YouTube.