[WPF] Style et Template: Ou comment faire pour séparer la logique métier du code de présentation
L'un des grands avantages de WPF (Windows Presentation Foundation) est qu'il permet aux développeurs et aux designers de travailler conjointement sur un projet sans que l'un d'entre eux ait besoin d'attendre qu'un autre finisse son travail pour pouvoir avancer 
Cette technique de travail peut, aux premiers abords, paraitre déroutante car elle n'a rien à voir avec ce que l'on fait au jour d'aujourd'hui. Mais au final, elle se révèle très performante et nous allons tenter de bien comprendre pourquoi et comment fonctionne ce mécanisme de travail développeur-designer.
Il y a 2 façons d'aborder un développement WPF:
- La première consiste à partir du principe que c'est le designer qui va mener le projet. A ce titre, c'est lui qui sera en charge de réaliser une maquette de toute l'interface graphique et le développeur n'aura plus qu'a récupérer cette ébauche pour commencer son développement.
- L'autre technique consite à partir du principe que c'est le développeur qui sera le meneur du projet. Il sera donc en charge d'esquisser une interface graphique sommaire mais qui suffira à ces besoins et le désigner n'aura plus qu'a travailler sur cette esquisse pour produire un rendu final correct.
Dans les 2 cas, le développeurs et le designer devront régulièrement fusionner leur travaux afin de commencer à produire l'application finale.
Mais comment est-ce possible ? Comment un développeur peut-il travailler sur une application WPF, alors que son design n'est pas encore fait/terminé ?
La réponse est simple et tiens en 2 mots: style et template 
Pour rappel, les styles correspondent, pour simplifier, à toute la partie "visuelle" des contrôles (couleur d'arrière-plan, couleur de la police, style de la police, etc...) et les templates, quand à eux, sont utilisé pour modifier la façon dont les contrôles sont affichés à l'écran. C'est grâce à eux que vous allez pouvoir dire que vous voulez que votre bouton ne soit plus un rectangle mais devienne un cercle ou ce que vous voulez d'ailleurs 
Ainsi, lors de la création du projet, une ébauche est établie:
<Window x:Class="TestItemsControl.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TestItemsControl" Height="300" Width="300"
>
<StackPanel Orientation="Vertical">
<TextBox x:Name="tb" />
<Button Content="Change" x:Name="btn" Click="ChangeClick" />
</StackPanel>
</Window>
Et le groupe de travail se sépare avec chacun (développeurs et designers) une copie de cette ébauche sur laquelle il vont travailler "localement".
Les développeurs ajouteront toute la logique métier de l'application (connexion à une base de données, utilisation de Web Services, etc....) tandis que les designers travailleront de leur coté pour produire les objets de type Brushes, Path, Style, Template, etc.... (exportés dans des ResourceDictionary) qui seront nécessaires à l'élaboration de l'interface finale.
Lors de leurs rencontres, développeurs et designers devront fusionner leur travaux. Cela peut-être fait par l'un ou l'autre mais on voit apparaitre, de plus en plus, le métier d'intégrateur WPF. Son rôle (comme vous pouvez vous en doutez) sera d'intégrer/de fusionner le travail des 2 parties pour fournir l'application finale.
Cet intégrateur, qui possède à la fois des compétences de développeur et des compétences de designer, devra donc fusionner les ResourceDictionary fournit par les designers et les utiliser au sein de l'application:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<ControlTemplate TargetType="{x:Type TextBox}" x:Key="tbTemplate">
<Grid x:Name="Grid">
<Border x:Name="Border" Background="Transparent" BorderBrush="Gray" BorderThickness="1" Padding="2" CornerRadius="2">
<ScrollViewer
Margin="0"
x:Name="PART_ContentHost"
Background="{TemplateBinding Background}"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
BorderThickness="{TemplateBinding BorderThickness}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Foreground="{TemplateBinding Foreground}"
/>
</Border>
</Grid>
</ControlTemplate>
</ResourceDictionary>
<Window x:Class="TestItemsControl.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TestItemsControl" Height="300" Width="300"
>
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Templates.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<StackPanel Orientation="Vertical">
<TextBox x:Name="tb" Template="{StaticResource tbTemplate}" />
<Button Content="Change" x:Name="btn" Click="ChangeClick" />
</StackPanel>
</Window>
Comme vous pouvez le constatez, utiliser les ResourceDictionary est assez simple: il suffit d'utiliser la collection MergedDictionaries pour ajouter les ResourceDictionary auxquels on souhaite avoir accès dans notre projets:
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Templates.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
Pour pouvoir appliquer le style/template, il suffit ensuite de l'appeler:
<TextBox x:Name="tb" Template="{StaticResource tbTemplate}" />
Maintenant, le plus gros du travail est fait: si un designer modifie un style ou un template, l'intégrateur n'aura qu'a remplacer le fichier XAML (ou juste les parties modifiées) et ne touchera plus au code (XAML et C#/VB.NET) de l'application.
Si vous êtes purement développeur et que vous développez vous-même vos propres styles/templates, sachez qu'il existe une technique qui vous permettra de les réutiliser sans avoir besoin de les réécrire. Frédéric Queudret, architecte au MTC Paris (Microsoft Technology Center), en a d'ailleurs fait une belle présentation sur son blog:
Externalisation des styles WPF en assembly satellite
La technique est relativement simple, facile à mettre en oeuvre et vous permettra de gagner pas mal de temps en terme de copier/coller 
A noter que cette technique peut également être appliquée au ResourceDictionary qui ont été créés par les designers mais ce sera plus le boulot de l'intégrateur (ou du développeur).
Voila, j'espère que cela vous sera utile :)
A+
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :