Windows Phone 8.1 - Crear un estilo para un Button

¡Hola geeks!

Hoy vamos a ver cómo crear un estilo de un Button. Voy a hacer este tutorial porque empezó siendo una idea fácil, pero luego me di cuenta de que el Button de por sí no me daba esas propiedades.

Idea

Crear un Button, de tal manera que pueda modificar su Background Color, Imagen y Opacidad en cada Button independientemente y que la opacidad afecte a la imagen.

Problema

El Button en sí. Para añadir una imagen como fondo debes prescindir del Color.

Alternativa

Bueno, a la alternativa a la que yo opté fue un RadHubTile de Telerik. Me permite crear un Style (estilo) de manera que puedo establecer un Color e Imagen a la vez. El inconveniente a este control es que si quiero que la opacidad afecte sólo a la imagen se aplicará a todos los elementos RadHubTile que tengo con ese estilo. Si quisiera que afectara la Opacidad al control entero, entonces me permitía hacerlo para cada control independientemente.

Reflexión

Volviendo al Button, creando un estilo me permitía establecer una imagen o un color y podía modificar su opacidad independientemente. Sólo le falta de alguna manera poder establecer un color y una imagen a la vez al Button. Justamente vamos a ver como hacer eso.

A continuación pongo a disposición el estilo del Button creado. Lo primero en lo que os tenéis que fijar es en el Grid que está dentro del ControlTemplate. Establecemos su Background a "PhoneAccentColor", que es el color del tema de móvil. Con esto nos aseguramos que el fondo sea por lo menos del color del tema del móvil.

Ahora tenemos que centrarnos en el rectángulo que hemos creado que está justo arriba de un Border. Su propiedad Fill está bindeada (enlazada) con la propiedad Content del Button. Esto quiere decir que cuando declaramos el Button, podemos en la propiedad Content establecer un color, y lo que hará que el rectángulo obtenga ese color. En la posición donde está, tapamos el Background del grid que establecimos antes con el "PhoneAccentColor" por el color establecido por el usuario en el rectángulo. Pero no tapamos la imagen que lo establecemos en el Border porque está más abajo.

Si os fijáis ahora en el Border, hay dos cosas importantes que tenéis que tener en cuenta. La primera que cuando desde el control Button establecemos el Background y ponemos una imagen (lo veremos a continuación), lo que estamos haciendo es establecer el Background del Border. La segunda y muy importante es dentro del Border, en el ContentControl poner la propiedad Content vacía. Con esto nos aseguramos de que el color que asignamos al rectángulo desde la propiedad Content no la mostremos como texto.

<Style x:Key="ButtonStyle" TargetType="Button"> <Setter Property="Background" Value="Transparent"/> <Setter Property="BorderBrush" Value="{StaticResource PhoneForegroundBrush}"/> <Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/> <Setter Property="BorderThickness" Value="{StaticResource PhoneBorderThickness}"/> <Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilySemiBold}"/> <Setter Property="FontSize" Value="{StaticResource PhoneFontSizeMedium}"/> <Setter Property="Padding" Value="10,5,10,6"/> <Setter Property="Margin" Value="5"></Setter> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <Grid> <Grid.Background> <SolidColorBrush Color="{StaticResource PhoneAccentColor}"/> </Grid.Background> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal"/> <VisualState x:Name="MouseOver"/> <VisualState x:Name="Pressed"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneButtonBasePressedForegroundBrush}"/> </ObjectAnimationUsingKeyFrames> <!--<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneAccentBrush}"/> </ObjectAnimationUsingKeyFrames>--> </Storyboard> </VisualState> <VisualState x:Name="Disabled"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ButtonBackground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground"> <DiscreteObjectKeyFrame KeyTime="0" Value="Transparent"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Rectangle Fill="{TemplateBinding Content}"></Rectangle> <Border x:Name="ButtonBackground" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" CornerRadius="0" Margin="30"> <ContentControl x:Name="ContentContainer" ContentTemplate="{TemplateBinding ContentTemplate}" Content="" Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/> </Border> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>

Finalmente, si queremos utilizar este estilo en nuestra aplicación, lo podemos poner en el App.xaml dentro de:

<Application.Resources> <ResourceDictionary> </ResourceDictionary> </Application.Resources>

Y por ejemplo en nuestro MainPage pongo un ejemplo de como utilizarlo:

<Button Command="{Binding HubButtonCommand}" Content="{StaticResource Indigo800}" Style="{StaticResource ButtonStyle}"> <Button.Background> <ImageBrush ImageSource="Assets/ButtonTiles/..." Opacity="1"></ImageBrush> </Button.Background> </Button>

Aquí podemos ver cómo establecemos la imagen, el color de fondo mediante la propiedad Content y la opacidad. Todo esto lo podemos Bindear y utilizarlo en nuestra ViewModel.

Bueno y aquí termina el pequeño "hack" que hemos hecho cambiado un poco el Template del Button para amoldarlo a nuestras necesidades.

Finalmente os muestro los dos estilos que creé para la elegir uno. El estilo de Telerik con su RadHubTile y el Button (el primero empezando por la izquierda). Si os fijáis son idénticos pero al final el Button me da más y me quedaré con el.

Para cualquier duda aquí estoy y, si os gusta no os lo quedéis para vosotros, compartid ;)

Happy Coding!