Crear una interfaz de usuario coherente mediante estilos
Los recursos son excelentes para evitar valores duplicados y codificados de forma rígida en el marcado XAML, pero pueden ser tediosos de aplicar. Cada valor de propiedad se asigna de forma individual, lo que da lugar a un XAML desordenado y detallado. En esta unidad se muestra cómo agrupar varias opciones de configuración en un estilo, lo que puede ayudar a ordenar su código y hacer que sea más fácil de mantener.
Cómo desordenan los recursos el XAML
Un recurso proporciona un valor para una sola propiedad. Sin embargo, el uso de una gran cantidad de recursos puede llevar a un XAML detallado. Imagine que quiere que los botones tengan un aspecto personalizado. En primer lugar tiene que crear recursos para los valores que necesita. Luego tiene que aplicar cada recurso a todos los botones. En el código siguiente se muestra el aspecto que tendría el código XAML para los dos botones.
<Button
Text = "OK"
BackgroundColor = "{StaticResource highlightColor}"
BorderColor = "{StaticResource borderColor}"
BorderWidth = "{StaticResource borderWidth}"
TextColor = "{StaticResource textColor}" />
<Button
Text = "Cancel"
BackgroundColor = "{StaticResource highlightColor}"
BorderColor = "{StaticResource borderColor}"
BorderWidth = "{StaticResource borderWidth}"
TextColor = "{StaticResource textColor}" />
Observe cómo las mismas cinco propiedades están establecidas en cada uno de los botones. El uso de recursos elimina la necesidad de valores repetidos y codificados de forma rígida en cuatro de ellos. Pero este tipo de marcado XAML se vuelve difícil de leer rápidamente. Además, si configura un gran número de propiedades para cada control, es fácil omitir accidentalmente una de ellas, provocando incoherencias en la apariencia de los controles. La solución es crear un estilo que asigne las cuatro propiedades a la vez.
¿Qué es un establecedor?
Los establecedores son los componentes clave que se usan para crear estilos.
Un establecedor es un contenedor para un par de propiedad y valor. Piense en un establecedor como el representante de una instrucción de asignación. Se especifica la propiedad que se va a asignar y el valor que se va a aplicar. Normalmente, los objetos Setter se crean en el marcado XAML. En el ejemplo siguiente se crea un objeto Setter para la propiedad TextColor.
<Setter Property="TextColor" Value="White" />
Puede usar un recurso para el valor de un establecedor, como se muestra en el código siguiente. Esta técnica es excelente cuando se quiere usar el mismo valor en varios establecedores.
<Setter Property="TextColor" Value="{StaticResource textColor}" />
Nota:
El valor de propiedad que se especifica en un establecedor se debe implementar como una propiedad enlazable. Todas las propiedades de los controles de .NET MAUI que terminan con el sufijo Property son propiedades enlazables. Si intenta usar una propiedad como TextColor en un establecedor, asegúrese de que haya una propiedad enlazable correspondiente denominada TextColorProperty en ese control. En la práctica, casi todas las propiedades que le interesa usar en los establecedores se implementan de este modo.
¿Qué es un estilo?
Un estilo es una colección de establecedores destinados a un tipo específico de control. .NET MAUI necesita el tipo de destino para asegurarse de que las propiedades de los establecedores existen en ese tipo.
En el código siguiente se muestra un estilo que combina los cuatro valores del ejemplo anterior. Observe que TargetType se establece en Button y que todas las propiedades de los establecedores son miembros de la clase Button. No puede usar este estilo para una etiqueta, porque la clase Label no incluye las propiedades BorderColor o BorderWidth.
<Style TargetType="Button">
<Setter Property="BackgroundColor" Value="#2A84D3" />
<Setter Property="BorderColor" Value="#1C5F9B" />
<Setter Property="BorderWidth" Value="3" />
<Setter Property="TextColor" Value="White" />
</Style>
Definir un estilo
Normalmente, los estilos se definen como recursos dentro de un objeto ResourceDictionary. Un diccionario de recursos facilita el uso del estilo en varios controles de la misma página o incluso en toda la aplicación. En el código siguiente se muestra cómo definir un estilo como un recurso dentro de un diccionario. Observe que el estilo recibe un nombre con la propiedad x:Key. Asignar un nombre a un estilo le permite hacer referencia a él desde dentro de las páginas XAML.
<ContentPage.Resources>
<Style x:Key="MyButtonStyle" TargetType="Button">
...
</Style>
</ContentPage.Resources>
Aplicar un estilo
Para adjuntar un estilo a un control, asigne el nombre a la propiedad Style. La asignación hace que todos los objetos Setter del estilo se apliquen al control de destino. En el código siguiente se muestra cómo aplicar el estilo de botón a dos botones.
<Button Text="OK" Style="{StaticResource MyButtonStyle}" />
<Button Text="Cancel" Style="{StaticResource MyButtonStyle}" />
En el ejemplo anterior, usó la extensión de marcado StaticResource para adjuntar el estilo a los controles. Esta técnica es excelente cuando no es necesario que el estilo cambie en tiempo de ejecución. Pero, ¿qué ocurre si quiere implementar, por ejemplo, temas dinámicos, donde la interfaz de usuario debe cambiar? En este caso, puede usar la extensión de marcado DynamicResource para cargar el estilo.
<Button Text="Cancel" Style="{DynamicResource MyButtonStyle}" />
DynamicResource escucha la sustitución de la propiedad x:Key en el diccionario de recursos. Si escribe un código que carga un nuevo estilo en ResourceDictionary con ese mismo valor x:Key, el nuevo estilo se aplicará automáticamente a la interfaz de usuario.
Usar un estilo implícito para varios controles
Imagine que la interfaz de usuario tiene 50 botones y que quiere aplicar el mismo estilo a todos ellos. Con lo que sabemos hasta ahora, tiene que asignar manualmente a la propiedad Style en cada botón. No es difícil, pero sí tedioso.
Un estilo implícito es un estilo que se agrega a un diccionario de recursos sin proporcionarle un identificador x:Key. Los estilos implícitos se aplican de forma automática a todos los controles del objeto TargetType especificado.
En el código siguiente se muestra el ejemplo anterior declarado como un estilo implícito. Este estilo se aplica a todos los botones de la página.
<ContentPage.Resources>
<Style TargetType="Button">
<Setter Property="BackgroundColor" Value="Blue" />
<Setter Property="BorderColor" Value="Navy" />
...
</Style>
</ContentPage.Resources>
Importante
La coincidencia de los estilos implícitos con controles requiere una coincidencia exacta con el objeto TargetType especificado. Los controles que se hereden del tipo de destino no recibirán los estilos. Si quiere que esto afecte a los controles heredados, puede establecer el atributo Style.ApplyToDerivedTypes en True al definir el estilo. Por ejemplo, para aplicar un estilo al tipo Button y que ello afecte a cualquiera de los botones que se hereden de Button (por ejemplo, ImageButton, RadioButton o un tipo personalizado que cree), podría usar un estilo como este.
<ContentPage.Resources>
<Style TargetType="Button"
ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor" Value="Black" />
</Style>
</ContentPage.Resources>
Invalidar un estilo
Piense que un estilo proporciona un conjunto de valores predeterminados para los controles. Un estilo existente podría cumplir casi todos sus requisitos, pero podría contener uno o dos establecedores que no quiere. En ese caso, podría aplicar el estilo y, a continuación, invalidar el valor estableciendo propiedades directamente. El valor explícito se aplica después del estilo, por lo que invalida al valor del estilo.
Imagine que quiere usar el estilo siguiente para varios botones de la página.
<Style x:Key="MyButtonStyle" TargetType="Button">
<Setter Property="BackgroundColor" Value="Blue" />
<Setter Property="BorderRadius" Value="10" />
<Setter Property="BorderWidth" Value="3" />
</Style>
Este estilo sirve para todos los botones excepto Cancelar, que necesita un fondo rojo. Puede usar el mismo estilo para el botón Cancelar siempre que también establezca directamente la propiedad BackgroundColor. En el código siguiente se muestra cómo invalidar el valor de color.
<Button
Text="Cancel"
Style="{StaticResource MyButtonStyle}"
BackgroundColor="Red"
... />
Selección de un tipo antecesor como destino
Imagine que quiere un color de fondo personalizado para los botones y las etiquetas. Puede crear estilos independientes para cada tipo o puede crear un estilo con TargetType establecido en VisualElement. Esta técnica funciona porque VisualElement es una clase base para Button y Label.
En el código siguiente se muestra un estilo que tiene como destino una clase base que se aplica a dos tipos derivados distintos.
<Style x:Key="MyVisualElementStyle" TargetType="VisualElement">
<Setter Property="BackgroundColor" Value="#2A84D3" />
</Style>
...
<Button Style="{StaticResource MyVisualElementStyle}" ... />
<Label Style="{StaticResource MyVisualElementStyle}" ... />
Este ejemplo identifica el estilo mediante x:Key y los controles lo aplican explícitamente. Un estilo implícito no funciona aquí, ya que el TargetType de un estilo implícito debe ser una coincidencia exacta con el tipo de control.
Usar BasedOn para heredar de un estilo
Imagine que quiere crear una apariencia coherente para la interfaz de usuario. Decide que todos los controles deben usar un color de fondo coherente. Es probable que la configuración del color de fondo aparezca en más de uno de los estilos. En el código siguiente se muestran dos estilos con un establecedor repetido.
<Style x:Key="MyButtonStyle" TargetType="Button">
<Setter Property="BackgroundColor" Value="Blue" />
<Setter Property="BorderColor" Value="Navy" />
<Setter Property="BorderWidth" Value="5" />
</Style>
<Style x:Key="MyEntryStyle" TargetType="Entry">
<Setter Property="BackgroundColor" Value="Blue" />
<Setter Property="TextColor" Value="White" />
</Style>
Puede usar la herencia de estilo para factorizar ese establecedor duplicado en un estilo base. Para crear un estilo derivado, establezca su propiedad BasedOn para hacer referencia al estilo base. El nuevo estilo hereda todos los establecedores de su estilo base. El estilo derivado también puede agregar establecedores nuevos o reemplazar un establecedor heredado por uno que contenga otro valor.
En el código siguiente se muestran los estilos del ejemplo anterior refactorizados en una jerarquía. El establecedor común solo aparece en el estilo base, en lugar de repetirse. Observe que usa la extensión de marcado StaticResource para buscar el estilo base. No puede usar DynamicResource en esta situación.
<Style x:Key="MyVisualElementStyle" TargetType="VisualElement">
<Setter Property="BackgroundColor" Value="Blue" />
</Style>
<Style x:Key="MyButtonStyle" TargetType="Button" BasedOn="{StaticResource MyVisualElementStyle}">
<Setter Property="BorderColor" Value="Navy" />
<Setter Property="BorderWidth" Value="5" />
</Style>
<Style x:Key="MyEntryStyle" TargetType="Entry" BasedOn="{StaticResource MyVisualElementStyle}">
<Setter Property="TextColor" Value="White" />
</Style>
El valor TargetType de los estilos base y derivado debe ser compatible. Para que los estilos sean compatibles, deben tener la misma propiedad TargetType o el TargetType del estilo derivado es un descendiente del TargetType del estilo base.