[WPF] Appliquez des thèmes dynamiquement dans vos applications

Le 11 juillet 2010 à 07:24

Dans mon post précédent, j’ai fait part d’une solution pour localiser vos applications sans passer par l’outil LocBaml. J’utilisais des ResourceDictionary que j’affectais dynamiquement au moment de l’exécution. Cette méthode peut être utilisée dans plusieurs cas, et l’une d’entre elle : les thèmes.
Devoir gérer plusieurs thèmes dans les applications était auparavant un travail assez complexe (je pense à la création de contrôle personnalisée, que la technologie WPF nous a permis de faire beaucoup plus simplement), mais maintenant avec les ResourceDictionary, c’est devenu relativement “simple”. Bien sûr, ceci n’est qu’un exemple d’application et il reste assez basique à mettre en place, mais cela pourra vous inspirer.

Nous allons créer deux thèmes : “default” et “light”. Pour cela, comme expliquer ci-dessus, nous allons ajouter des ResourceDictionary (dictionnaire de ressources en français) :

image


Maintenant, nous allons remplir ces fichiers :

<!-- Default.xaml -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:System="clr-namespace:System;assembly=mscorlib">

    <System:String x:Key="ThemeName">Default</System:String>
    <SolidColorBrush x:Key="win_background" Color="DarkBlue"></SolidColorBrush>

    <Style TargetType="Button">
        <Setter Property="FontFamily" Value="Verdana"/>
        <Setter Property="FontSize" Value="10px"/>
        <Setter Property="FontWeight" Value="Bold"/>
        <Setter Property="Background" Value="LightBlue" />
    </Style>
</ResourceDictionary>



<!-- Light.xaml -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:System="clr-namespace:System;assembly=mscorlib">

    <System:String x:Key="ThemeName">Light</System:String>
    <SolidColorBrush x:Key="win_background" Color="LightBlue"></SolidColorBrush>

    <Style TargetType="Button">
        <Setter Property="FontFamily" Value="Trebuchet MS"/>
        <Setter Property="FontSize" Value="10px"/>
        <Setter Property="FontWeight" Value="Normal"/>
        <Setter Property="Background" Value="White" />
    </Style>
</ResourceDictionary>

Puis la déclaration dans le point d’entrée de l’application du thème par défaut :

<Application x:Class="WPFThemes.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Themes\Default.xaml"></ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

Maintenant que tout cela est fait, on va implémenter la méthode qui va nous permettre de changer de thème dynamiquement dans le point d’entrée de notre application :

public partial class App : Application
{
    private ResourceDictionary obj;

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        foreach (ResourceDictionary item in this.Resources.MergedDictionaries)
        {
            if (item.Source != null && item.Source.OriginalString.Contains(@"Themes\"))
            {
                obj = item;
            }
        }
    }

    public void ChangeTheme(Uri dictionnaryUri)
    {
        if (String.IsNullOrEmpty(dictionnaryUri.OriginalString) == false)
        {
            ResourceDictionary objNewLanguageDictionary = 
                                   (ResourceDictionary)(LoadComponent(dictionnaryUri));

            if (objNewLanguageDictionary != null)
            {
                this.Resources.MergedDictionaries.Remove(obj);
                this.Resources.MergedDictionaries.Add(objNewLanguageDictionary);
            }
        }
    }
}

Il faut savoir que quand on utilise beaucoup de ResourceDictionary, il peut se produire un impact négatif sur les performances : ce sera mon prochain article :).

Maintenant pour pouvoir lié notre interface avec les styles :

<Window x:Class="WPFThemes.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        Background="{DynamicResource ResourceKey=win_background}">
    <Grid>
        <Button Content="Changer le thème" Height="51" HorizontalAlignment="Center" 
          Name="btnChangeTheme" VerticalAlignment="Center" Width="110" 
          Click="btnChangeTheme_Click" />
    </Grid>
</Window>

Pour télécharger les sources, ici.

A bientôt !

Ajouter un commentaire

biuquote
  • Commentaire
  • Prévisualiser
Loading

A propos de l'auteur

Mathieu Perrein - Software Solutions Manager, Software Architect, Trainer MCT, MSP de 2010 à 2012.

 

MSP

 

MSP

MSP

 MSPD

MCT

 

Facebook

 

Ce blog est strictement personnel et les opinions exprimées ici n'engagent donc que moi, et pas mon employeur.

Tags

Vous avez désactivé JavaScript ou bien vous possédez une ancienne version d'Adobe Flash Player. Téléchargez la dernière version de Flash Player.