Professional Documents
Culture Documents
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.
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" :
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" :
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.
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 :
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 :
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 :
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 :
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 :
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"
xmlns:local="clr-namespace:ArticleCreationControlesWPF"
A prsent, dans votre application, il ne vous reste plus qu faire appel votre contrle :
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 !