Vous êtes sur la page 1sur 10

Comment crer votre propre contrle avec WPF

Windows Presentation Foundation offre un grand nombre de contrles disponible pour dvelopper vos applications. Cet article vous permettra de voir les deux options qui vous sont offertes si vous souhaitez, vous-mme, crer votre propre contrle.

Avec Windows Presentation Foundation, il existe 2 moyens, offerts aux dveloppeurs, pour dvelopper leurs propres contrles. Tout dabord, ils peuvent crer un contrle utilisateur ("UserControl"). Lautre possibilit est dhriter dun contrle dj existant. Chacune de ces techniques possde ses avantages et ses inconvnients que nous allons dtailler dans la suite de cet article. Lobjectif est de vous permettre de faire le bon choix lorsque vous serez amen vous poser la question de comment faire pour dvelopper votre contrle.

Crer un contrle utilisateur


Windows Presentation Foundation permet de crer ce que lon appelle des contrles utilisateur ("User Controls"). Si vous tes dveloppeur WindowsForms ou WebForms, cette notion ne doit pas vous tre trangre car cest un mcanisme utilis trs souvent. Le but des contrles utilisateur est de vous permettre de dvelopper un contrle qui est compos dautres contrles. Pour que cela soit plus simple comprendre, prenez lexemple dun formulaire de connexion. Il sagit dune chose que lon fait trs souvent : une page/un formulaire compos de labels, de zones de saisies et de boutons. Si vous deviez dvelopper une dizaine de fois un tel formulaire, vous vous rendriez vite compte que le code utilis est toujours le mme et que trs peu de diffrences existent entre chacune des versions. Pour vous viter davoir crire plusieurs fois la mme chose, il est possible de regrouper ces contrles dans un contrle utilisateur, que vous dposerez sur vos formulaires : vous gagnez ainsi en temps de dveloppement !

Avec WPF, il sagit dune technique tout fait envisageable/utilisable dans vos projets. Pour crer ce type de contrle, rien de plus simple : dans Visual Studio, fates un clic droit sur votre projet et choisissez "Add" => "User Control" :

L, Visual Studio vous demande le nom de votre contrle :

A ce moment l, le contrle est automatiquement ajout votre projet et vous disposez du designer WPF de Visual Studio pour dfinir le contenu de votre contrle. Si lon regarde le code behind, on se rend compte que votre contrle utilisateur nest rien dautre quune classe qui hrite de la classe "UserControl" :

public partial class DemoUC : UserControl

Cependant, vous pouvez vous demander quels sont les avantages/intrts de crer un contrles de ce type. Le premier avantage rside dans le fait que les contrles utilisateur supportent les contenus riches. Autrement dit, vous pouvez mettre ce que vous voulez (et au nombre que vous voulez) dans le code de votre contrle. Le deuxime avantage de ces contrles est simple mais trs utilis dans le cadre dun dveloppement WPF : ils supportent les styles et les triggers. Pour rappel, les styles sont utiliss pour dfinir lapparence dun contrle (les couleurs, les styles de polices, etc.) tandis que les triggers sont des actions effectues lorsquune condition est vrifie.

Bien que pratique, les contrles utilisateur possdent un dsavantage important quil faudra toujours bien garder lesprit : ils ne supportent pas les templates. De ce fait, ils ne peuvent pas tre customiss afin dtre reprsents diffremment (via lutilisation dun ControlTemplate).

Pour savoir si la cration dun contrle utilisateur est ce que vous devez faire, rpondez ces deux questions : Votre contrle est-il compos dautres composants existants ? Pouvez-vous vous passer de la customisation de votre contrle ?

Si la rponse est "Oui" chaque fois, alors il ny a pas hsiter : ce quil vous faut est un contrle utilisateur !

Il est important de noter que ce type de contrle possde une limitation : le binding, les animations, etc. ne sont pas supports en l'tat et il faut passer par des DependencyProperty.

Hriter dun contrle existant


Hriter dun contrle existant pour crer votre propre contrle est une autre technique envisageable. Celle-ci vous permet bien plus de possibilits quimplmenter un contrle utilisateur mais se trouve tre lgrement plus complexe mettre en place. Utiliser les "Custom Controls" (cest le nom que lon donne aux contrles que lon cr via cette technique) vous offrira lavantage de bien sparer linterface utilisateur du contrle et sa logique oprationnelle via lutilisation de templates, cela afin doffrir le maximum de flexibilit.

Pour crer un "Custom Controls", rien de plus simple avec Visual Studio. Fates un clic droit sur votre projet et choisissez "Add" => "New Item" :

L, rendez-vous sur le nud "WPF", slectionnez "Custom Control (WPF)", entrez le nom "CheckedComboBox.cs" et cliquez sur "Add" :

A ce moment l, Visual Studio va rajouter plusieurs lments votre projet : Un rpertoire "Themes" avec un fichier "Generic.xaml" : cest dans ce fichier que nous allons dfinir, via du code XAML, lapparence de notre contrle Un fichier contenant la logique de notre contrle (CheckedComboBox.cs)

Comme vous pouvez le constater, Visual Studio fait, de lui-mme, la sparation entre le code C# et linterface. Maintenant, vous pouvez vous demander comment fait le moteur WPF pour savoir quel est le style appliquer et o le trouver. Pour savoir quil y a un style particulier appliquer votre contrle, WPF se fie cette ligne, crite dans le constructeur statique de la classe reprsentant votre contrle :

DefaultStyleKeyProperty.OverrideMetadata(typeof(CheckedComboBox), new FrameworkPropertyMetadata(typeof(CheckedComboBox)));

Via cette ligne, nous informons le moteur WPF que le style par dfaut du contrle est surcharg. A prsent, il faut lui indiquer o aller chercher ce nouveau style par dfaut. Pour cela, encore une fois, vous navez rien faire car Visual Studio a fait le travail pour vous : si vous ouvrez le fichier "AssemblyInfo.cs", vous remarquerez ce code :

[assembly: ThemeInfo( ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly )]

Cette portion de code est utilise pour indiquer o (entendez par l dans quelle assembly .NET) se trouve les dictionnaires de ressources (dont le gnrique) utiliser si une ressource nest pas trouve dans la page, dans lapplication ou dans un dictionnaire de ressource spcifique un thme.

Maintenant que nous savons comment cela fonctionne, il est temps de le mettre en pratique. La premire chose que nous allons faire, cest modifier la classe parente de notre contrle. En effet, par dfaut, nous hritons de la classe "Control", qui est la classe parente de tous les contrles WPF. Cest un bon dbut mais dans notre cas, nous voulons crer une classe qui sapparente plus la ComboBox (avec des fonctionnalits supplmentaires) : il convient donc de spcifier que nous souhaitons hriter de ce contrle :

public class CheckedComboBox : ComboBox

Une fois cette tape fate, nous allons crire linterface utilisateur de notre ComboBox personnalise. Pour cela, ouvrez le fichier "Generic.xaml" et remplacez le code suivant :

<Style TargetType="{x:Type local:CheckedComboBox}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:CheckedComboBox}"> <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style>

Par ce code :

<Style x:Key="{x:Type local:CheckedComboBox}" TargetType="{x:Type local:CheckedComboBox}" BasedOn="{StaticResource {x:Type ComboBox}}"> <Setter Property="ItemContainerStyle"> <Setter.Value>

<Style TargetType="{x:Type ComboBoxItem}" > <Setter Property="Margin" Value="2, 2, 2, 0" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ComboBoxItem}"> <Border Background="Transparent" x:Name="borderSelect"> <CheckBox Content="{TemplateBinding Content}" x:Name="chkSelect" /> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> </Setter.Value> </Setter> </Style>

Regardons de plus prs ce que fait ce code. Nous dfinissons un style, qui sappliquera tous les contrles de type CheckedComboBox. Dans ce style, nous redfinissons le style de la proprit ItemContainerStyle. Ensuite, nous appliquons un style (sur tous les lments de type ComboBoxItem) dont nous modifions le template pour quil soit compos dune bordure incluant une case cocher. On ne peut plus simple non !?

A prsent, nous allons modifier le constructeur de notre contrle pour spcifier que nous voulons, sur le clic dune ComboBox, appeler une mthode spcifique. Pour cela, nous allons utiliser la mthode AddHandler, qui prend en paramtres lvnement intercepter et un dlgu, qui reprsente la mthode appeler :

public CheckedComboBox() : base() { this.AddHandler(CheckBox.ClickEvent, new RoutedEventHandler(chkSelect_Click)); }

Maintenant, il nous faut crire le code de la mthode chkSelect_Click, qui sera charge, chaque clic sur une case cocher, de rcuprer le contenu de lensemble des lments slectionns pour les afficher dans notre ComboBox. Voici donc le code de cette mthode :

private void chkSelect_Click(object sender, RoutedEventArgs e) { string TextToDisplay = string.Empty;

foreach (ComboBoxItem item in this.Items) { Border borderSelect = item.Template.FindName("borderSelect", item) as Border; if (borderSelect != null) { CheckBox chkSelect = borderSelect.FindName("chkSelect") as CheckBox; if (chkSelect != null) { if (chkSelect.IsChecked.GetValueOrDefault()) { if (!string.IsNullOrEmpty(TextToDisplay)) { TextToDisplay += ", "; } TextToDisplay += chkSelect.Content; } } } } if (!string.IsNullOrEmpty(TextToDisplay)) { // Remove item from the list if (ItemToDisplay != null) { if (this.Items.Contains(ItemToDisplay)) { this.Items.Remove(ItemToDisplay); } } // Add item to the list for displaying the text ItemToDisplay = new ComboBoxItem(); ItemToDisplay.Content = TextToDisplay; ItemToDisplay.Visibility = Visibility.Collapsed; this.Items.Add(ItemToDisplay); this.SelectedItem = ItemToDisplay; } }

Lors de lappel de cette mthode, nous parcourons lensemble des lments de notre ComboBox. Sur chacun de ces lments, nous accdons la bordure (via son nom) puis nous accdons au contenu de la case cocher (l encore via son nom) pour le stocker dans une chane de caractres. Comment estce possible ? Tout simplement car nous avons dfini, dans le template de notre contrle, un style qui sapplique aux lments de notre ComboBox et nous avons, dans ce style, indiqu que les lments taient en fait compos dune bordure incluant une case cocher (reportez-vous au contenu du fichier Generic.xaml en cas de doute).

Enfin, une fois que nous avons parcouru tous les lments, nous crons un nouveau ComboBoxItem dont le contenu est la chane de caractres utilise pour stocker le contenu de chacune des cases cocher ! Comme cela est sans doute un peu abstrait, testez le contrle pour vous rendre compte du rsultat. Pour cela, ouvrez le fichier Window1.xaml et trouvez la ligne suivante :

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Juste en dessous, ajoutez cette ligne de code :

xmlns:local="clr-namespace:ArticleCreationControlesWPF"

A prsent, dans votre application, il ne vous reste plus qu faire appel votre contrle :

<local:CheckedComboBox Width="150" Height="25"> <ComboBoxItem>Un</ComboBoxItem> <ComboBoxItem>Deux</ComboBoxItem> <ComboBoxItem>Trois</ComboBoxItem> <ComboBoxItem>Quatre</ComboBoxItem> <ComboBoxItem>Cinq</ComboBoxItem> </local:CheckedComboBox>

A lexcution, vous constatez que vous obtenez bien une ComboBox dont les lments sont des cases cocher. De plus, chaque fois que vous slectionnez/dslectionnez un lment, lensemble des lments cochs apparait dans la ComboBox :

Comme vous pouvez le voir, nous avons bien russi sparer la logique de notre contrle de son interface graphique. Bien sur, le contrle que nous avons dvelopp est simpliste et loin dtre optimis (il aurait par exemple fallut utiliser un StringBuilder pour stocker le texte, etc.) mais il vous permet de vous rendre compte des possibilits techniques.

Conclusions
Comme vous avez pu vous en rendre compte, les 2 techniques voques prcdemment possdent chacune leurs points forts et leurs points faibles. Cest vous, dveloppeur WPF/.NET, de bien valuer vos besoins et faire le bon choix. Enfin, si la cration de contrles personnaliss vous intresse, je vous recommande de regarder le fameux "BagOTrick" de Kevin Moore (http://j832.com/bagotricks/) ou bien le projet Codeplex WPFDeveloperTools (dont je suis lauteur et qui est disponible ladresse suivante : http://www.codeplex.com/WPFDeveloperTools) : en effet, ils contiennent tous les deux un grand nombre de contrles et les tudier vous permettra de bien maitriser ce concept et les diffrents patterns qui y sont lis !

Thomas Lebrun Consultant/Formateur Microsoft MVP C#