Dot.Blog

C#, XAML, Xamarin, UWP/Android/iOS

Personnaliser un thème du toolkit Silverlight

[new:28/01/2011]Les thèmes fournis avec le toolkit Silverlight (ou en version WPF) sont bien pratiques pour obtenir rapidement un visuel propre sans investir des heures pour créer un ensemble de styles. Toutefois on ressent souvent le besoin de les personnaliser, de changer un petit détail. Hélas, autant l’utilisation des DLL de thèmes sont pratiques autant elles sont hermétiques à toute modification... Regardons comment personnaliser un thème du toolkit et surmontons ce mur qui n’est finalement pas infranchissable.

Les thèmes

Il existe deux moyens d’appliquer un style dans Silverlight, soit en utilisant les styles implicites soit en utilisant les styles explicites. Lapalisse n’aurait pas pu trouver plus évident !

La différence essentielle entre ces deux formes de styles tient dans leur effet : un style implicite s’applique automatiquement à toute une classe de contrôle sans avoir besoin de le préciser au niveau de chacun d’eux. Un style explicite nécessite une déclaration qui l’est tout autant dans le contrôle qui doit recevoir le dit style.

Cette nuance se traduit non pas par une syntaxe différente mais plutôt par une sorte de ruse : les style explicites doivent avoir un nom (x:Key) puisqu’ils appartiennent à un dictionnaire de styles (traduit côté code par un dictionnaire<> qui n’accepte donc pas les clés nulles, ni les clés redondantes).

La ruse tient dans le fait que les style implicites ne doivent pas déclarer de nom (x:Key), en apparente violation avec les règles de gestion des dictionnaires de styles. Mais laissons cette “plomberie” et ses mystères aux concepteurs de Silverlight ce n’est pas l’objet de ce billet. Ce qui nous intéresse ici est de savoir faire la différence entre ces deux formes de styles et de savoir les déclarer.

Un thème est donc tout simplement un ensemble de styles implicites contenu généralement dans un seul fichier XAML. Un thème permet d’obtenir un visuel cohérent tout au long d’une application.

Le toolkit de Silverlight fourni plusieurs thèmes qui ne sont pas forcément merveilleux, sauf le thème Expression Dark car il reprend le look de Expression Blend logiciel dont vous savez mon amour inconditionnel... Merveilleux ou non, ces thèmes offrent un visuel cohérent rapidement et permettent d’échapper au look XP de base qui est assez atroce tout en évitant l’investissement énorme que peut représenter la création d’un thème ex-nihilo.

Motivation

Les thèmes du toolkit sont fournis en version DLL et en version source XAML. Si on désire d’emblée créer un thème personnalisé on peut bien entendu utiliser le source XAML. Mais souvent il arrive qu’on soit parti sur la version DLL, plus rapide à mettre en œuvre mais qu’on veuille, à un moment donné du développement, personnaliser un élément...

Un exemple qui m’est arrivé et qui peut motiver une telle personnalisation : Dans un logiciel pour lequel moi et mon infographiste avions conçu un look simple et épuré j’avais utilisé le thème Expression Dark qui se mariait bien avec le design qui avait été créé. L’utilisation d’un thème permettait ici (et c’est une méthode réutilisable par tous) d’avoir à la fois un look très original puisque créé pour le client sans avoir à définir un style pour chaque contrôle (boutons, sliders, listbox...). Justement, parlons des listbox. C’est au moment de créer le DataTemplate pour l’une d’entre elles que le problème s’est posé. La largeur du DataTemplate ne s’adapte pas à la largeur de la listbox mais à celle du contenu. C’est un piège classique que j’aurai du anticiper (mea culpa est) d’autant plus que j’avais écris un billet sur le sujet l’année dernière (Largeur de DataTemplate et Listbox). Faut-il être distrait (et écrire tellement de choses !) pour tomber dans un tel panneau... Heureusement grâce à Dot.Blog (qui me sert souvent d’aide mémoire !) j’ai retrouvé facilement la solution. Elle consiste à ajouter quelques lignes de XAML à la Listbox pour fixer un style qui modifie l’alignement horizontal de l’ItemContainer.

Or, cette astuce, en fixant un style local à la Listbox interdit l’application du style implicite du thème du toolkit ! C’est tout le thème de la listbox qui tombe ainsi à l’eau. Deux solutions, soit réinventer le thème Expression Black de la Listbox, soit customiser le thème du toolkit.

On en revient au sujet du présent billet ...

Personnaliser un thème du Toolkit

Pour passer d’un thème du toolkit à une version personnalisée de ce dernier encore faut-il avant toute autre chose passer du thème automatique en DLL au même thème en version Xaml modifiable sans faire tomber toute l’application.

Première étape : de la DLL au source Xaml du thème

Quelques étapes vont être nécessaires pour passer de l’un à l’autre. Selon le nombre de pages utilisant la DLL la manip sera plus on moins longue mais en général  l’ensemble de la modification se fait assez vite, surtout en suivant le guide :

Phase 1 : Localiser le source Xaml du thème

Il faut dans un premier temps localiser le code source Xaml du thème que vous utilisez dans l’application. Je vais prendre l’exemple du thème Expression Black dans le reste du billet. Ce code source se trouve sur ma machine dans :
C:\Program Files (x86)\Microsoft SDKs\Silverlight\v4.0\Toolkit\Apr10\Themes\Xaml

(j’utilise Windows 7 / 64 bits, le chemin peut être légèrement différent si vous utiliser un OS 32b ou plus ancien).

Phase 2 : copie de la source Xaml

Une fois le fichier repérer, copiez-le dans le répertoire Assets ou Skins de votre application Silverlight (le répertoire que vous avez réservé pour les dictionnaires de styles).

Je vous conseille de renommer le fichier pour éviter toute confusion avec l’original, d’autant que nous faisons cette manip en vue de le modifier.

Phase 3 : suppression de la DLL

Comme le projet utilisait en référence la DLL du thème Expression Dark, il va être nécessaire de supprimer cette dernière. A la place il faut ajouter une référence à la DLL “Theming” du Toolkit (System.Windows.Controls.Theming).

Phase 4 : correction de l’espace de noms

Dans chaque Vue de votre application utilisant la DLL il va être nécessaire de modifier la déclaration des namespaces pour ajouter “Theming” :

xmlns:theming="clr-amespace:System.Windows.Controls.Theming;
assembly=System.Windows.Controls.Theming.Toolkit" 

Phase 4 : Correction des balises

La DLL originale n’est plus référencée, le code source Xaml du thème a été rapatrié, le namespace du Theming du Toolkit a été ajouté à chaque Vue. Reste à supprimer la balise de l’ancien thème et à la remplacer par “theming:Theme”.

L’ancien code ressemblait à cela :

<toolkit:ExpressionDarkTheme >
        <Grid x:Name="LayoutRoot">
            ... ... ...
        </Grid>
</toolkit:ExpressionDarkTheme>

Le nouveau sera le suivant :

<theming:Theme>
        <Grid x:Name="LayoutRoot">
           ... ... ...
        </Grid>
</theming:Theme>

Phase 5 : Incorporer le nouveau dictionnaire

Ajouter le fichier Xaml du thème dans le projet n’est pas suffisant... Encore faut-il le référencer dans la liste des dictionnaires de ressources gérées dans App.Xaml :

<Application.Resources>
  <ResourceDictionary>
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="Skins/MainSkin.xaml"/>
        <ResourceDictionary Source="Skins/MyExpressionDark.xaml"/>
    </ResourceDictionary.MergedDictionaries>
  </ResourceDictionary>
</Application.Resources>

Phase 6 : La peur ! Smile

Lancez la construction de votre projet et faites vous peur !

Tout est cassé et vous vous prenez une volée de bois vert de la part du compilateur. Des erreurs par kilos, voire par tonnes.

La cause première de la plupart des erreurs que vous verrez est simple : le fichier Xaml de ressource du thème qui a été ajouté au projet fait référence à des tas d’espaces de noms, notamment ceux du Toolkit. Il est fort probable que votre projet ne les références pas tous à cet instant précis de votre développement.

Globalement deux solutions s’offrent à vous : Ajouter l’ensemble des espaces de noms manquant dans les références du projet ou bien supprimer tous les styles du thème qui posent problème (et que vous n’utilisez pas pour le moment sinon votre projet aurait déjà la référence de leur espace de nom).

Personnellement je vous déconseille la seconde approche. Qui vous dit que dans deux jours ou deux mois vous n’aurez pas besoin d’ajouter tel ou tel autre contrôle ? Si vous avez supprimer les définitions de style dans le thème il faudra les recréer. Pour l’instant je vous conseille donc uniquement d’ajouter toutes les références qui manquent.

Bien entendu en ajoutant toutes les DLL du Toolkit à votre projet celui-ci risque d’enfler un peu ! Ce n’est pas forcément souhaitable, un gros fichier Xap est toujours un handicap. Mais laissez les choses en l’état et pensez à faire le ménage une fois la V 1.0 de votre application sera prête à être releasée. C’est plus sage.

Une fois tous les espaces de noms référencés correctement dans le projet ce dernier devrait se compiler à nouveau correctement.

A noter une petite curiosité dans le thème que j’ai utilisé dans l’exemple : en début de manœuvre je vous ai dit qu’il fallait déréférencer la DLL du thème puisque nous allions utiliser le code source Xaml. C’est vrai. Mais pour raison étrange le code source XAML référence lui-même la DLL ce qui dans la dernière étape oblige à la remettre en place. Bien entendu j’ai tenté de la mettre en commentaire trouvant la situation ridicule... Plantage à l’exécution. En référençant la DLL tout est rentré dans l’ordre. Je n’ai pas d’explication immédiate, je vous tiendrai au courant si je trouve (le temps de trouver) !

Pour connaitre la liste des espaces de noms nécessaires, ouvrez tout simplement dans Visual Studio le fichier thème Xaml que vous avez ajouté. En début de fichier se trouve toutes les références utilisées. Normalement les références manquantes sont soulignées d’une ligne ondulée d’erreur. Il suffit d’ajouter les références utilisées par l’ensemble de ces lignes plutôt que de farfouiller partout quel espace de nom est manquant (je pense que cela fonctionne dans VS de base et que ce n’est pas une aide de Resharper, outil indispensable que j’utilise depuis si longtemps qu’il m’est impossible de vous dire si un VS “nu” supporte ou non telle ou telle commande...).

Phase 7 : Pause café !

C’est fini pour la première partie, la plus dure. Il est temps de faire un petit Commit vers Subversion et d’aller se fumer un café (en prenant soin de se couvrir en conséquence, l’été est encore loin !). Les plus sobres iront boire un verre d’eau du robinet et s’abstiendront (avec raison) d’allumer une cigarette...

Seconde étape : La personnalisation proprement

Ca y est ? vous êtes prêt ? Alors c’est bon, il ne vous reste plus qu’à modifier les styles du thème puisque désormais ils sont intégrés en code source dans votre projet (utilisez Blend de préférence).

Le billet s’arrête là... Vous amener jusqu’à ce point était son but, maintenant à vous de jouer !

Conclusion

Utiliser les DLL des thèmes est autrement plus pratique que d’utiliser les sources Xaml. Nous l’avons vu, la DLL sait se passer de tout un tas de référence que le code Xaml oblige à ajouter au projet. Moins simple à manier, plus lourd côté référence, la version source n’a pas que des avantages, mais elle laisse la porte ouverte à toutes les personnalisation du thème et cela peut être crucial.

Que votre motivation soit purement esthétique ou technique (comme je l’expliquais en début de billet dans mon cas), il arrivera fatalement un jour où vous aurez besoin de personnaliser un thème du toolkit. Ce jour là, il vous suffira de retrouver ce billet et d’avoir une pensée pour votre serviteur grâce à qui vous pourrez aller tranquillement en pause café au lieu de rester scotcher devant votre PC Smile

Forcément : Stay Tuned !

blog comments powered by Disqus