Tema personalizado en Windows Phone Mango


Vintage Phone Embroidery Hoop ArtEn la versión anterior de Windows Phone 7 crear un tema personalizado para nuestra aplicación era bastante sencillo. Bastaba con copiar el fichero ThemeResource.xaml que se encontraba en la carpeta en %programfiles%\Microsoft SDKs\Windows Phone\v7.0\Design y luego hacíamos un Merge de los diccionarios de recursos.

Según Peter Torr esto se podía hacer debido a un “bug” de Silverlight 3 que en el 4 está solucionado. Fuera o no un bug era bastante útil; en Mango usamos Silveright 4 así que tendremos que trabajar un poco más, pero aún podremos hacerlo. La recomendación de Peter Torr es usar estilos implícitos o bien actualizar los estilos del tema. En Windows Phone Geek han encontrado una manera de utilizar el ThemeResource.xaml, pero se han dejado algún paso, o no han probado a poner el tema del dispositivo/emulador en modo claro (light), así que os voy a contar cómo lo hago yo.

Vamos a combinar las dos técnicas y lo explicado en Windows Phone Geek para ahorrarnos el tedioso trabajo de crear todos los estilos de todos los controles de nuevo.

Creación y aplicación de tema personalizado

1. Copiaremos el fichero ThemeResource.xaml, que ahora lo encontramos en %programfiles%\Microsoft SDKs\Windows Phone\v7.1\Design, a una carpeta de nuestra solución, por ejemplo Themes:

2. Una vez copiado, cambiaremos su BuildAction a Resource para que la carga sea más rápida:

3. Editamos los colores del ThemeResource.xaml que hemos copiado a nuestra solución; podemos, por ejemplo, cambiar el color del Accent a un rojo claro:

<Color x:Key="PhoneAccentColor">#FFFF2828</Color>

4. Ahora, en el App.Xaml.cs creamos un método que nos permita copiar los valores del diccionario de recursos sobre los valores por defecto, tal como proponen en Windows Phone Geek:

private void MergeCustomColors()
{
    var dictionaries = new ResourceDictionary();
    string source = string.Format("/{0};component/Themes/ThemeResources.xaml",
        new System.Reflection.AssemblyName(
        this.GetType().Assembly.FullName).Name);
    var themeStyles = new ResourceDictionary { Source = new Uri(source, UriKind.Relative) };
    dictionaries.MergedDictionaries.Add(themeStyles);

    ResourceDictionary appResources = App.Current.Resources;
    foreach (DictionaryEntry entry in dictionaries.MergedDictionaries[0])
    {
        SolidColorBrush colorBrush = entry.Value as SolidColorBrush;
        SolidColorBrush existingBrush = appResources[entry.Key] as SolidColorBrush;
        if (existingBrush != null && colorBrush != null)
        {
            existingBrush.Color = colorBrush.Color;
        }
    }
}

5. Desde el constructor de App llamamos al método para que se efectúe la copia lo antes posible:

public App()
{
    // Global handler for uncaught exceptions.
    UnhandledException += Application_UnhandledException;

    // Standard Silverlight initialization
    InitializeComponent();

    // Phone-specific initialization
    InitializePhoneApplication();

    //Carga del esquema de colores:
    MergeCustomColors();
...

Si os habéis fijado en el método MergeCustomColors habréis visto que lo único que hacemos es ir actualizando los colores de todos los elementos Brush. El diccionario de recursos es read-only, así que no podemos reasignar los valores, sólo podemos cambiar propiedades de esos valores y en el caso de Color no es posible.
Esto tiene un problema y es que el LayoutRoot tiene el color predefinido a Transparent y toma el color de fondo del ApplicationFrame, que en lugar de utilizar un Brush utiliza directamente un Color.

Si ejecutamos nuestra aplicación en modo claro no veremos casi nada:

6. Para resolver el problema del fondo no nos quedará más remedio que cambiar el color de fondo para toda la aplicación. Podríamos ir pantalla por pantalla y cambiar el color de fondo de cada LayoutRoot a negro, pero no nos hará falta. Gracias a los estilos implícitos nos bastará con cambiar el color en el App.Xaml para el PhoneApplicationFrame:

<!--Application Resources-->
<Application.Resources>
    <Style TargetType="phone:PhoneApplicationFrame">
        <Setter Property="Background" Value="Black"/>
    </Style>
</Application.Resources>

Así conseguiremos ver todo el contenido correctamente.

Últimos retoques

Ahora que ya vemos correctamente nuestra aplicación en los colores que nosotros deseamos podemos dar un poco más de coherencia al tema si cambiamos también el color del ApplicationBar. Como no es un control no podremos controlar su aspecto con los estilos implícitos (o por lo menos yo no he sabido), así que o bien usamos una barra para toda la aplicación en el Application.Resources o tendremos que cambiar los colores en cada página donde tengamos una barra:

    <phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True" 
               BackgroundColor="Black" ForegroundColor="White">
        ...

También se puede esconder la barra de sistema, pues en modo claro aparecerá también de color blanco, aunque no es recomendable pues a muchos usuarios les gusta saber qué hora es mientras usan la aplicación.
Para esconderla hay que editar también cada página y cambiar el valor shell:SystemTray.IsVisible a False.

Para probar con las nuevas maneras de cambiar los estilos es necesario utilizar el SDK7.1 de Windows Phone

Espero que os sirva de utilidad y si encontráis una forma mejor de hacerlo ¡compartid! 😀

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s