Sie sind auf Seite 1von 78

Formations .

NET Audit, Conseil, Formation, Dveloppement

Articles gratuits tlcharger www.e-naxos.com Dot.Blog, le blog www.e-naxos.com/blog

Copyright 2010 Olivier DAHAN MICROSOFT MVP C# 2009, MVP Client App Dev 2010

Reproduction, utilisation et diffusion interdites sans lautorisation de lauteur. Pour plus dinformation contacter odahan@e-naxos.com

Le BINDING Xaml Matriser sa syntaxe et viter ses piges (WPF / Silverlight)


Version 1.0 Avril 2010

Sommaire
Rfrences ........................................................................................................................................... 5 Code Source ........................................................................................................................................ 6 Prambule ........................................................................................................................................... 7 Le Binding Xaml : Ange ou Dmon ? ................................................................................................ 7 Le Binding ........................................................................................................................................... 8 Dfinition ........................................................................................................................................ 8 Utilisations ...................................................................................................................................... 9 Schma du principe ........................................................................................................................ 9 Dclaration ..................................................................................................................................... 10 Par code ...................................................................................................................................... 10 En Xaml ....................................................................................................................................... 11 Les modes de binding.................................................................................................................... 13 Le mode OneTime ..................................................................................................................... 13 Le mode OneWay ...................................................................................................................... 13 Le mode TwoWay ...................................................................................................................... 14 Gestion du timing .................................................................................................................. 14 Le mode Default ........................................................................................................................ 16 Le mode OneWayToSource ...................................................................................................... 16 Hirarchie de valeur ...................................................................................................................... 18 Rgles de prcdences ............................................................................................................... 19 La notion de DataContext ........................................................................................................... 20 Les convertisseurs de valeur ......................................................................................................... 21 Dfinition ................................................................................................................................... 21 Scnario ...................................................................................................................................... 21 Implmentation .........................................................................................................................22 Utilisation ................................................................................................................................... 23 Instanciation .......................................................................................................................... 23 Invocation............................................................................................................................... 23 Bonnes pratiques .................................................................................................................. 24 Pour rsumer ......................................................................................................................... 26 Les dangers du Binding .....................................................................................................................27 Des chanes non contrles ..........................................................................................................27 Un langage dans le langage .......................................................................................................... 28
Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

On fait quoi ? .................................................................................................................................... 28 Dboguer le Binding......................................................................................................................... 28 Vigilance ........................................................................................................................................ 28 Une code Xaml court .................................................................................................................... 29 Refactoring sous contrle ............................................................................................................ 29 Utiliser des outils intelligents ...................................................................................................... 29 Utiliser Expression Blend ............................................................................................................. 29 Vrifier les erreurs de binding dans la fentre de sortie ............................................................ 30 Crer un fichier des erreurs de Binding ...................................................................................... 30 La feinte du convertisseur inutile ................................................................................................. 32 Quelques outils supplmentaires ................................................................................................. 33 Spy++ .......................................................................................................................................... 33 ManagedSpy ............................................................................................................................... 33 Snoop ......................................................................................................................................... 34 Mole ........................................................................................................................................... 34 Reflector .................................................................................................................................... 34 Vos neurones ............................................................................................................................. 34 Les syntaxes du Binding ................................................................................................................... 34 Le binding simple ......................................................................................................................... 34 Binding direct ............................................................................................................................ 35 Binding sur une proprit ......................................................................................................... 35 Binding sur une sous-proprit du contexte .......................................................................... 36 LElement Binding ..................................................................................................................... 37 Convertisseurs de valeur ........................................................................................................... 37 Paramtres de conversion .................................................................................................... 38 StringFormat ............................................................................................................................. 40 Injection de culture ............................................................................................................... 41 Le ContentStringFormat ...................................................................................................... 42 Grer les nuls......................................................................................................................... 43 Le Binding Multiple ...................................................................................................................... 44 La classe Personne .................................................................................................................... 44 Le code du multi convertisseur ............................................................................................... 45 Le code Xaml ............................................................................................................................. 46 Le Binding XML ............................................................................................................................ 47

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

Binding sur une source Web .................................................................................................... 47 Binding sur une source XML en ressource ............................................................................. 48 Binding sur une requte Linq To XML ................................................................................... 49 Le Binding Relatif ..........................................................................................................................52 Binding to Self ............................................................................................................................52 Le TemplatedParent Binding .................................................................................................... 53 Le Binding sur recherche danctre ......................................................................................... 54 Le Binding PreviousData .......................................................................................................... 56 La source de donnes ........................................................................................................... 58 La visibilit des flches : la magie de PreviousData et du Binding Multiple .................... 58 Le contenu des textes ............................................................................................................ 61 Le Template binding ................................................................................................................. 61 Utilit ...................................................................................................................................... 61 Le Collection Binding ................................................................................................................... 67 Le Priority Binding ....................................................................................................................... 69 Les proprits de tous les bindings ................................................................................................. 74 Conclusion ........................................................................................................................................ 76

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

Table des figures


Figure 1 - Exemple de Binding minimaliste ____________________________________________________ 11 Figure 2 - Le mode OneTime ________________________________________________________________ 13 Figure 3 - Le mode OneWay ________________________________________________________________ 13 Figure 4 - le mode TwoWay ________________________________________________________________ 14 Figure 5 - Convertisseur de valeur en action ___________________________________________________24 Figure 6 - Binding direct ___________________________________________________________________ 35 Figure 7 - binding sur une proprit __________________________________________________________ 35 Figure 8 - Accs une sous proprit du DataContext __________________________________________ 36 Figure 9 - Element Binding _________________________________________________________________ 37 Figure 10 - StringFormat en US______________________________________________________________ 41 Figure 11 - ContentStringFormat_____________________________________________________________43 Figure 12 - ContentStringFormat corrig ______________________________________________________43 Figure 13 - Binding XML __________________________________________________________________ 48 Figure 14 - Binding XML depuis un fichier en ressource _________________________________________ 49 Figure 15 - Binding sur le rsultat d'une requte Linq To Xml _____________________________________ 51 Figure 16 - Binding to Self __________________________________________________________________ 52 Figure 17 TemplatedParent Binding _________________________________________________________ 53 Figure 18 - Binding sur recherche d'anctre ____________________________________________________54 Figure 19 - Binding sur recherche d'anctre avec niveau de profondeur _____________________________ 55 Figure 20 - Binding PreviousData ____________________________________________________________ 57 Figure 21 - Template Binding Cration du template sous Blend _________________________________ 62 Figure 22 - Template binding - application du template 1/2 ______________________________________ 63 Figure 23 -Template binding - application du template 2/2 ______________________________________ 63 Figure 24 - Template binding - Essai de changement de Background ______________________________ 64 Figure 25 - Template binding - cration du lien sous Blend ______________________________________ 65 Figure 26 - Le button correctement templat _________________________________________________ 65 Figure 27 - Le Collection Binding ___________________________________________________________ 67 Figure 28 - Priority Binding - 1/3 ____________________________________________________________ 70 Figure 29 - Priority Binding - 2/3 ___________________________________________________________ 70 Figure 30 - Priority Binding - 3/3 ____________________________________________________________ 71

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

Rfrences
Vous trouverez ici lensemble des rfrences indiques dans le cours de larticle afin de pouvoir visiter les liens sans ncessairement fouiller dans le texte.

Nota : tous les liens ont t vrifis la date dcriture de larticle. Internet est un monde en perptuel mouvement, si une rfrence venait ne plus tre valide, nhsitez pas me le signaler pour que je mette le lien jour.

M-V-VM et Silverlight De la thorie la pratique http://www.e-naxos.com/Blog/post/2010/01/09/Article-M-V-VM-avec-Silverlight.aspx Le retour du spaghetti vengeur http://www.e-naxos.com/Blog/post/2010/03/13/Le-retour-du-spaghetti-vengeur.aspx lElement Binding http://www.e-naxos.com/Blog/post/2009/07/23/Silverlight-3-LElement-Binding.aspx Simple MVVM http://www.e-naxos.com/Blog/post/2010/02/24/Simple-MVVM.aspx MVVM, Unity, Prism, Inversion de controle
http://www.e-naxos.com/Blog/post/2009/12/23/MVVM-Unity-Prism-Inversion-of-Controle280a6.aspx Les proprits de dpendance et les proprits jointes http://www.e-naxos.com/Blog/post.aspx?id=ee3a2372-acd9-4650-a1d9-76ce4f21e483

Model-View-ViewModel http://blogs.msdn.com/johngossman/archive/2005/10/08/478683.aspx Reshaper http://www.jetbrains.com/resharper/ Trace sources in WPF http://blogs.msdn.com/mikehillberg/archive/2006/09/14/WpfTraceSources.aspx How Can I debug WPF bindings ? http://bea.stollnitz.com/blog/?p=52 Spy++ http://msdn.microsoft.com/en-us/library/aa264396(VS.60).aspx Snoop http://blois.us/blog/2006/08/long-time-since-my-last-post-but-dont_21.html Mole http://karlshifflett.wordpress.com/mole-for-visual-studio/ ManagedSpy http://www.microsoft.com/france/msdn/windows/ManagedSpy.mspx Reflector http://www.red-gate.com/products/reflector/index.htm String Format options http://idunno.org/archive/2004/14/01/122.aspx WPF Multibinding http://www.switchonthecode.com/tutorials/wpf-tutorial-using-multibindings PreviousData Binding http://jimmangaly.blogspot.com/2008/12/discovering-relativesourcepreviousdata.html Contrasting Silverlight and WPF http://msdn.microsoft.com/en-us/library/dd458872.aspx

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

Code Source
Cet article est accompagn du code source complet de lapplication exemple si tel nest pas le cas vous pouvez tlcharger la version complte (PDF + code) sur le site e-naxos (voir la premire page de ce document). Dcompressez le fichier Zip dans un rpertoire de votre choix. Le code utilise Visual Studio 2008 et Expression Blend 3.

Rpertoire Sample0 Sample1 Sample2 Sample3 Sample4 Sample5 Sample6 Sample 7 Sample8

Projet
ConverterSample WpfMiniBinding SimpleBinding XmlBinding RelativeBinding PreviousDataBinding TemplateBinding ListBinding PriorityBinding

Page
21 8 34 47 52 56 61 67 69

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

Prambule

e Binding (quon traduira par ligature ou simplement lien en franais) est un pilier fondateur de Xaml, donc de WPF et Silverlight. Il sagit de pouvoir relier deux proprits de deux objets de telle faon { ce que tout changement dans lune soit automatiquement report dans lautre (voire dans les deux sens selon le mode choisi). Apportant une grande richesse Xaml, le Binding est implment dans ce langage sous la forme dextensions au sein des balises, les commandes tant exprimes en chaines de caractres non contrles la compilation. A la fois cet tat de fait et le ct opaque de la syntaxe peuvent tre sources de bugs ou de difficults. Cet article fait le point sur ces dernires, la syntaxe et le dbogue du Binding Xaml. Note : Le prsent article est fourni avec des projets exemples et les extraits de codes qui sont proposs en sont majoritairement issus. Par souci pratique lensemble des exemples a t ralis sous WPF avec VS 2008 pour que la plus grande partie des lecteurs puisse en profiter. Il existe quelques nuances entre WPF et Silverlight, tout ce qui est montr dans cet article ne sapplique pas forcment ce dernier. Le lecteur pourra consulter le site MSDN pour connatre les diffrences existantes un instant donn (la convergence WPF/Silverlight saccentuant chaque release la frontire est toujours mouvante). Voir dans les Rfrences de larticle (page 5) pour les liens.

Le Binding Xaml : Ange ou Dmon ?


Dans la pratique le Binding occupe une place essentielle car il vite beaucoup de code behind, simplifie lcriture des applications orientes donnes (on parle de Data Binding), clarifie les changes entre contrles visuels et code (via un DataContext par exemple) ou dautres contrles visuels (on parle dElement Binding). Le Binding est ainsi logiquement au cur des bonnes pratiques de programmation sous Silverlight et WPF, et se retrouve mme propuls la place de moteur indispensable { lapplication de patterns telle que Model-View-ViewModel dont je vous ai longuement entretenu dans un prcdent article M-VVM et Silverlight De la thorie la pratique . Sur Dot.Blog jai lanc il y a quelques temps un pav dans la mare de cette mcanique superbe mais fragile. Le billet Le retour du spaghetti vengeur retrace avec un peu dhumour un audit mayant permis de constater { quel point limplmentation totalement non contrle du Binding sous Xaml (puisquil sagit de chanes de caractres non vrifies la compilation) pouvait reprsenter un rel danger. Dans ce billet je mettais aussi au dfi les aficionados de Xaml de me citer de tte toutes les combinaisons possibles de lextension Binding. Que cela soit parmi mes lecteurs ou les amis et clients { qui jai soumis cette question, je nai jamais eu de rponse complte. Preuve en est que la chose reste confuse et mrite certainement quon sy attarde quelques instants. Si lon rapproche ces deux faits, { savoir que le Binding est au cur de toute programmation effectue en suivant les bonnes pratiques, et le constat que peu de dveloppeurs matrisent

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

totalement le sujet, on en arrive la conclusion du billet voqu plus haut : le code spaghetti fait son grand retour, ce qui peut tre fatal la technologie elle-mme (Je renvoie le lecteur mon billet pour le dtail du raisonnement qui est ici raccourci { lextrme pour viter les redites). Comme je souhaite cette critique positive, car les errements font partie de ladoption de toute nouvelle technologie et quautant WPF que Silverlight mritent un effort, il ma sembl naturel de faire le point sur ces problmes et sur les solutions possibles pour les viter. Le prsent article ntait donc pas rellement un cours sur le Binding au dpart, plutt une collection de conseils et des prcisions de syntaxe. Mais au fil de lcriture il est peut-tre devenu le cours le plus complet quon puisse trouver { ce jour (et gratuitement) sur le sujet ! Jai malgr tout choisi daborder cet article comme une aide la comprhension et au dbogue du Binding ce qui passe par un point syntaxique assorti dexemples pour fixer les choses, et, je lespre, rendre plus clair cette extension essentielle de Xaml. Car trangement, si le Binding lui-mme est largement discut et doctement dissqu par de nombreux auteurs, le ct pratique est souvent survol et ses dangers et ambigits sont systmatiquement passs sous silence. Peut-tre que la raison est quil est plus facile de parler thoriquement dune nouveaut quon a par force peu pratique et dont on ignore les chaussetrappes alors quil est autrement plus difficile den parler pratiquement parce que lon sen sert au quotidien et quon a engrang une vritable exprience. En tout cas cest bien de vcu et de pratique quotidienne que je souhaite vous parler ici.

Le Binding
Fixons le dcor. Quest-ce que le Binding, quoi sert-il et comment le dclare-t-on ?

Dfinition
Le Binding (ou ligature) est un moyen de crer une connexion entre deux proprits dinstances quelconques, une dans chaque instance. Le lien lui-mme est matrialis par une instance dune classe spcialise de Binding qui possde son paramtrage propre prcisant le comportement du lien tabli. La communication ainsi instaure permet une valeur de ragir immdiatement aux changements de lautre (la valeur de la source est copie dans la valeur cible) sans avoir besoin de programmer du code de gestion dvnement (typiquement PropertyChanged ou ses versions spcialises comme Checked ou UnChecked dun CheckBox par exemple). Si la communication tablie est totalement rciproque on parle alors de mode TwoWay (double sens), sinon de mode OneWay (sens unique).

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

Utilisations
Le Binding est largement utilis pour coupler des classes mtiers (des donnes au sens large) linterface utilisateur. Lavnement de patterns comme M-V-VM renforce encore limportance du binding dans laide quelles apportent la sparation nette entre interface utilisateur et code applicatif. Dans ce cas, mme les commandes ou les vnements dinterface vont tre binds (lis) des proprits dune classe particulire en charge des actions (le ViewModel dans MVVM). Je revoie le lecteur la section

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

Rfrences page 5 du prsent document pour obtenir les adresses des billets et articles que jai crits sur ces sujets. Le principe est en fait trs ancien, Delphi, VB, Java, les Windows Forms, toutes ces technologies ont propos des moyens de crer du binding . Les plus anciennes utilisaient des classes spcialises et le binding ne sentendait que dans le cadre trs restrictif dune connexion une base de donnes. Les technologies plus modernes comme Java, Windows Forms, ASP.NET, ouvraient la notion de binding en objectivant les sources de donnes, ce qui a marqu une tape dcisive dans lvolution du concept. Crer un lien (gnralement TwoWay, { double sens) entre des donnes et des lments de lIU est ainsi, historiquement en tout cas, la principale utilisation du Binding. Xaml a repris lobjectivation du Binding des Windows Forms et de ASP.NET en lamplifiant et en crant une syntaxe particulire permettant de dfinir ces liens entre objets de faon dclarative au sein dun format SGML1. La connotation base de donnes SQL est alors dfinitivement abandonne. Si des donnes proviennent dune telle source, cest au travers de couches spcialises (le DAL2 par exemple) qui les transforment de toute faon en objets et listes dobjets (voire en grappes comportant des sous graphes). Si Windows Forms ouvrait la voie une utilisation trs tendue du Binding grce llargissement du concept de source de donnes tout objet, Xaml a consacr ce qui ntait au dpart quun artifice spcialis { lpoque de Delphi en outil de premire classe pour dvelopper autrement. Cest cet autrement qui nous intresse plus particulirement aujourdhui notamment au travers de MVVM et de constructions comme Prism, et qui, par lutilisation accrue du binding rvlent plus encore ses difficults de mise en uvre et de dbogue.

Schma du principe

OneWay Objet de binding Source

Cible

TwoWay

La proprit dun objet cible est lie { la proprit de lobjet source via un objet de binding. Cet objet contient les informations du lien et gre les changements de valeurs pour les propager dans un sens ou les deux selon le mode choisi. Lorsquon dfinit un binding il y a toujours une source et une cible, mme implicite. De fait le sens de la dfinition compte (principalement en mode OneWay). En mode TwoWay les deux proprits peuvent tre considres la fois comme source et cible.
1 2

SGML, voir http://fr.wikipedia.org/wiki/Standard_Generalized_Markup_Language D.A.L. : Data Access Layer, Couche dAccs aux Donnes.

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

10

Dclaration
Le Binding se dclare soit directement dans le code Xaml, soit par code classique (C#, VB.NET). Par code On peut dfinir un binding par code. Cela est parfois trs utile mme si cette faon de faire reste marginale. Si on suppose un TextBox ainsi dfini dans le code Xaml :
<TextBox x:Name="MaTextBox" />

On peut crer un binding entre la proprit Text de ce TextBox et nimporte quelle proprit dun autre objet, par exemple la proprit TimeOfDay dune variable DateTime :
// binding minimaliste var currentTime = DateTime.Now; var binding = new Binding("TimeOfDay") { Source = currentTime, Mode = BindingMode.OneWay }; MaTextBox.SetBinding(TextBox.TextProperty, binding);

Rpertoire : Sample1 Projet : WpfMiniBinding

On est ici dans le cadre le plus minimaliste qui soit. Dabord la source est un objet trs simple (un DateTime), dans la ralit on trouvera plus souvent des objets mtiers complexes ou un ViewModel3, et ensuite le type de binding effectu est sens unique (OneWay) ce qui veut dire que seul lobjet cible sera mis jour. Ce qui donnera laffichage suivant :

Figure 1 - Exemple de Binding minimaliste

Bien entendu, lobjet source tant une valeur fixe (nous prenons lheure que nous stockons dans une variable qui est utilise ensuite pour le Binding, donc une valeur fige), lheure

Code grant la logique dune vue dans la pattern M-V-VM (voir les Rfrences page 3 pour larticle complet ce sujet)

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

11

affiche nvolue pas. Cest bien du Binding minimaliste, car la source nimplmente aucun mcanisme pour rafraichir la valeur. Un DateTime nest pas un timer, juste un moyen de connatre la date et lheure { un moment donn. De fait, le lien dfini en mode OneWay (qui supporte le rafraichissement de la source pour le propager la cible) est inutile et nous aurions pu prfrer un mode OneTime (initialisation de la cible une seule fois). Pour un affichage un peu plus vivant il faudrait dfinir une classe fournissant lheure mais qui sache aussi prvenir quand celle-ci change. Nous allons voir cela dans lexemple suivant (projet source : WpfMiniBinding) qui contient une classe Horloge capable de remplir cette fonction. En Xaml La faon la plus frquente de dfinir un binding est de le faire directement dans le code Xaml. Je vais utiliser ici une classe Horloge cre pour loccasion. Cette classe supporte linterface INotifyPropertyChanged qui dclenche PropertyChanged toutes les 500 ms par un timer interne. Elle expose une proprit Heure qui retourne lheure depuis la classe DateTime. Il ny a pas de stockage de lheure, cette dernire est lue depuis DateTime chaque accs la proprit. Lvnement PropertyChanged est dclench arbitrairement deux fois par seconde par le timer. Il suffit ds lors de crer un binding avec la proprit Heure pour tre averti deux fois par seconde que le contenu a chang, ce qui est exploit ici pour mettre jour automatiquement un TextBox.
public class Horloge : INotifyPropertyChanged { private Timer timer; public Horloge() { timer = new Timer(500); timer.Elapsed += timer_Elapsed; timer.Start(); } public string Heure { get { return DateTime.Now.TimeOfDay.ToString(); } } void timer_Elapsed(object sender, ElapsedEventArgs e) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Heure")); } public event PropertyChangedEventHandler PropertyChanged; }

Puisquil sagit dune dfinition en mode Xaml, nous nallons pas crer linstance de la classe Horloge par code C# (ce qui serait possible), nous allons directement le faire en Xaml en crant une ressource dans le corps de la fentre en cours (lapplication exemple est en WPF, on pourrait crire le mme type de code sous Silverlight) :

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

12

<Window.Resources> <local:Horloge x:Key="Horloge" /> </Window.Resources>

Lespace de noms local est dfini dans lobjet Window pour pointer sur lassemblage du programme :
xmlns:local="clr-namespace:WpfMiniBinding"

Ensuite cest dans la dfinition de MaTextBox2 que nous allons lier la proprit Text de cette dernire la ressource statique Horloge . Il faut prciser quelle proprit de cette classe nous souhaitons lier Text. Ce qui sexprimera de la faon suivante :
<TextBox Text="{Binding Source={StaticResource Horloge}, Path=Heure, Mode=OneWay}" Name="MaTextBox2" />

Une fois cette dfinition en place, vous aurez la joie de voir lheure dfiler dans le TextBox, mme en mode design sous Visual Studio (ou Blend) !

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

13

Les modes de binding


Jai voqu jusquici quelques uns des modes de binding, par exemple le mode OneWay ou le TwoWay qui sont les principaux utiliss. Mais Il existe plusieurs modes de binding adapts des situations bien prcises. Un mauvais choix du mode de binding peut aussi entraner des bogues fonctionnels sournois. Il est donc ncessaire davoir clairement { lesprit lutilit et la logique de chacun des modes disponibles et de toujours dclarer explicitement le mode. Le mode OneTime Le mode OneTime, une fois , comme son nom lindique va initialiser la valeur cible une seule fois, ds que le binding sera interprt sil est dcrit en Xaml, ou ds quil sera excut sil est dfini par code. Ce mode est trs utile pour les valeurs qui ne changent pas en cours dexcution dun programme (ou dune fentre). Dans le projet exemple fourni avec larticle le premier TextBox reli une variable DateTime lest par un binding OneTime puisque la valeur dorigine ne changera jamais (le code du projet est ainsi construit, le code exemple plus haut utilise OneWay) La logique du mode OneTime peut se voir comme suit :

Initialisation de la proprit Source et lecture de sa valeur

Initialisation de la valeur de la Cible

Figure 2 - Le mode OneTime

La squence dmarre par la reconnaissance de la source et elle sarrte immdiatement aprs que la valeur de cette dernire a t reporte sur la valeur cible. Les vnements de changement de la source qui pourraient intervenir sont ignors. Le mode OneWay Dans ce mode la cible est initialise puis lobjet de binding surveille les changements de valeur de la source et met jour la cible si un tel vnement se produit. Si la cible est modifie par dautres voies, la source reste inchange. Schmatiquement le mode OneWay ragit de la faon suivante :
Oui Initialisation de la proprit Source et lecture de sa valeur Initialisation de la valeur de la Cible Attendre notification de changement de la source Non La Source a chang ?

Figure 3 - Le mode OneWay

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

14

Le mode OneWay est dutilisation frquente lorsquil sagit de relier une source de donnes { un affichage non interactif, par exemple un TextBlock, un Chart, etc. Le mode TwoWay Cest un mode destin { tout binding de type interactif. Il dfinit un lien { double sens. Dans un premier temps la cible est mise jour partir de la valeur de la source. Comme dans le cas du OneWay, si la source change la cible sera mise jour. Mais le suivi a aussi lieu dans lautre sens : si la cible est modifie la modification sera reporte sur la source. Source et cible jouent ainsi un rle qui semble quivalent mais il y a une subtile nuance dans la squence dinitialisation qui fait que ces rles sont bien distincts. Schmatiquement le mode TwoWay agit comme suit :
Oui Initialisation de la proprit Source et lecture de sa valeur Attendre notification de changement de la source et de la cible Non Mettre jour la valeur de la Source La cible a chang ?

Initialisation de la valeur de la Cible

La Source a chang ?

Oui

Non

Figure 4 - le mode TwoWay

Gestion du timing Le mode TwoWay propose une option intressante mais dlicate utiliser, UpdateSourceTrigger qui permet de modifier le timing de la mise jour de la source du binding lorsque la cible change. Je dis dlicate utiliser car utiliser cette option complexifie encore la balise de dfinition du binding et peut, par le degr de nuance introduit dans le comportement global tre source derreurs. Sinon loption en elle-mme ne pose gure de difficults particulires. Pour illustrer son fonctionnement prenons un exemple. Imaginons que la proprit Text dun TextBox est relie la proprit Nom dune instance de type Personne (un objet mtier) cest un binding TwoWay qui sera gnralement utilis : lorsque la fiche Personne est connecte la cible TextBox il faut que la valeur de la proprit Nom soit propage la proprit Text du TextBox. Cest le sens naturel : de la source vers la cible. Mais lorsque lutilisateur souhaite corriger le nom de la personne, cest la cible qui est modifie. Dans un systme interactif on souhaite bien entendu que cette modification soit reporte sur la source (la proprit Nom de linstance de Personne).

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

15

Plusieurs possibilits soffrent { nous. La premire serait de ragir au changement de contenu du TextBox, mais alors la source sera mise jour chaque frappe de caractre. Si le Setter de la proprit Nom de la classe Personne interdit par exemple les noms vides ou les noms de moins de deux caractres il sera impossible deffacer le nom en cours pour en taper un autre Au dbut le nom sera vide donc rejet par la proprit Nom. De mme corriger en gommant les derniers caractres dun nom court risque dchouer sil reste moins de deux caractres (contrle du Setter de Nom). Dans le cas dun TextBox on saperoit que le timing offert par un simple PropertyChanged risque de provoquer plus dennuis quautre chose Nous voquons ici une proprit Nom dont le contenu est par dfinition assez ouvert. Imaginons une cl daccs qui doit tre formate correctement avant dtre accepte, cest tout au long de la frappe que lutilisateur recevra des messages derreur, jusqu{ ce quil termine sa frappe dune cl bien forme Le Framework tant bien fait il nous permet grce { loption UpdateSourceTrigger de contrler le type dvnement qui dclenchera la mise jour de la source quand la cible changera. Pour un TextBox cest lvnement LostFocus qui sera utilis par dfaut par exemple. Ces modes par dfaut sont dfinis proprit par proprit par le concepteur du contrle. On dispose ainsi des options suivantes pour UpdateSourceTrigger :
Default. Pour la majorit des proprits cest PropertyChanged qui dclenche la mise

jour. Mais on remarquera que la proprit Text de certains contrles possde par dfaut un autre comportement : la mise jour est dclenche sur LostFocus. PropertyChanged. La source est immdiatement modifie ds que la cible change de valeur. LostFocus. La source est mise jour uniquement quand la cible perd le focus. Explicit. La source nest pas mise { jour automatiquement, il faut appeler explicitement UpdateSource qui est une mthode de lobjet BindingExpression.

La dernire option est assez tortueuse car lorsque le binding est dfini en Xaml on ne dispose pas de lobjet de binding et encore moins de lobjet BindindExpression. Dans ce cas il faut rcuprer ce dernier depuis lobjet qui dfinit le binding. Pour illustrer ce cas supposons un TextBox dfini comme suit :
<TextBox Name="MaTextBox" Text="{Binding Path=LaPropritSource, UpdateSourceTrigger=Explicit}" />

Pour faire un UpdateSource il faudra crire le code suivant :


BindingExpression be = MaTextBox.GetBindingExpression(TextBox.TextProperty); be.UpdateSource();

Tout cela complique les choses malgr tout et un code qui reposerait sur lutilisation de telles astuces serait certainement trs difficilement maintenables. Je vous conseille dviter ces options complexes qui rpartissent de la logique la fois dans le Xaml et le code C#. Mieux

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

16

vaut tout grer par code C#, en crivant des gestionnaires dvnement appropris. On y perd certes un peu dans la dmonstration de force du programmeur mais on y gagne beaucoup niveau maintenabilit, et cest un critre primordial pour un code professionnel. Bien entendu dans certains cas justifis techniquement, bien encadrs et documents se servir de toute la puissance du binding nest pas interdit ! Le vritable danger est le risque que chaque dveloppeur dune quipe, selon ses comptences, utilise ou non certaines subtilits. On obtient au final un code htrogne difficile maintenir et o chaque intervention fait peser des risques de rgression (imaginez que le dveloppeur ayant la moins grande exprience du binding soit oblig dintervenir sur une partie comportant des nuances quil ne comprend pas). Le mode Default Ce mode existe et il faut bien faire attention lui ! En effet beaucoup de personnes pensent que lorsque le mode de binding nest pas indiqu cest le mode OneWay qui sapplique (dautres dailleurs pensent que cest le TwoWay), or par dfaut, cest le mode Default qui est utilis ! Et son fonctionnement varie en fonction du mode de binding par dfaut dfini au niveau de la cible par le concepteur du contrle ! Ainsi, un CheckBox a un mode par dfaut TwoWay, ce qui semble logique mais qui nest donc pas OneWay Pour viter les erreurs de comprhension il est toujours prfrable de fixer le mode explicitement. Se reposer sur la connaissance des modes par dfaut de chaque contrle nest pas raisonnable pour un code professionnel qui se doit dtre maintenable facilement. Une supplique un peu hors sujet : il en va de mme pour les niveaux de prcdences des oprateurs dans un calcul. Evitez le snobisme qui consiste ne placer aucune parenthse en basant toute la logique du calcul sur la prcdence des oprateurs. Cela est difficile maintenir, et se trouve tre une source frquente de rgression : on ajoute un terme au calcul pour une volution du code et cest tout le calcul qui prend un autre sens. Placez toujours des parenthses dans vos calculs, vous dmontrerez ainsi votre professionnalisme bien plus quen rendant votre code impossible maintenir ! Jai vu maintes fois en audit des erreurs difficiles dboguer provenir de ce style de programmation. Le mode OneWayToSource Ce mode l est un peu une curiosit. Il nexiste pas sous Silverlight et javoue ne lavoir jamais vu utiliser. Dans le mode OneWayToSource on retrouve ainsi la mme logique que dans le mode OneWay sauf que cest la source qui est modifie par la cible et non linverse. Etrange et source de confusion et derreur, { viter sauf si cela simpose. Car bien entendu parfois cela simpose Les dveloppeurs du Framework ne sont ni fous ni stupides, loin sen faut. Il y a forcment une raison intelligente { lexistence de ce mode de binding un peu tonnant. Elle existe et bien peu la connaissent. Posons dabord le fait que tout binding sopre sur des proprits de dpendances, et exclusivement sur des proprits de ce type, en tout cas en ce qui concerne la source (voir mon article sur les proprits de dpendances section Rfrences en dbut darticle). Dans certains cas il peut savrer ncessaire de faire un binding avec une

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

17

proprit CLR comme source. Ce nest pas lesprit de Xaml mais parfois on peut tre coinc et ne pas avoir dautres possibilits. Le Mode OneWayToSource autorise un tel binding et il est invers car la proprit CLR ne peut pas tre la source dun binding elle ne peut donc tre que la cible. Mais si on dsire quelle joue le rle de source il faut bien inverser le fonctionnement du binding lui-mme. Cest l{ la raison dtre de ce mode trange. Sen servir autrement nest vraiment pas recommand. A noter que la dfinition dun binding OneWayToSource propose la mme option que le mode TwoWay concernant le timing du binding pour la mise jour de la source. (voir le mode TwoWay).

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

18

Hirarchie de valeur
Le binding, parce quil joue sur des proprits de dpendance et parce quil nest quune possibilit parmi dautres de donner une valeur une proprit de ce type, ncessite de bien comprendre la hirarchie que le moteur des proprits de dpendance utilise pour fixer la valeur courante dune telle proprit. Pour comprendre limportance de cette hirarchie reprenez lexemple de code fourni et discut plus haut dans cet article. Il se compose de deux TextBox, la seconde tant mise jour par un objet Horloge . Sa proprit Text (qui est la cible) change ainsi chaque fois que la proprit Heure de lhorloge change (cest la source). Telle quest conue lapplication, deux fois par seconde le texte du second TextBox change. Cest la consquence directe du binding mis en place. Cela fonctionne mme en conception comme nous lavons vu. Excutez lapplication. Le texte du second TextBox change rgulirement. Placer le focus sur ce contrle et tapez quelques lettres (une suffit en ralit). Que se passe-t-il ? Lhorloge est casse En effet, le texte nest plus mis { jour. Vous tentez deffacer les caractres que vous avez taps, mais rien ny fait. Le texte ne change plus. Pourquoi ? Cest une consquence des rgles de prcdence pour lattribution de la valeur courante dune proprit de dpendance. Ici, en tapant quelque chose dans le TextBox vous avez cr une valeur locale pour la proprit Text. Or, une valeur locale la prcdence sur presque tout, dont un binding. Effacer les caractres saisis ny change rien, plus vous agissez sur le TextBox plus vous confirmez que lutilisateur souhaite quil prenne une valeur locale ! Rien ny fait, lhorloge est casse. On pourrait penser que lutilisation de ClearValue saurait, en supprimant la valeur locale, rtablir le fonctionnement de lhorloge. Il nen est rien. Le binding nexiste plus. En ralit le binding est considr comme une valeur locale. En en saisissant une nouvelle, ou en leffaant par ClearValue on dtruit donc la valeur locale, donc le binding. Rien ne peut le faire revenir, sauf relancer lapplication (ou reconstruire par code le binding) Vous comprenez facilement maintenant pourquoi je souhaite vous parler de cette hirarchie : elle est en elle-mme une possible source de bogues souvent difficiles dceler. La premire des choses { comprendre est quune proprit de dpendance peut avoir plusieurs valeurs la fois tant que ces valeurs sont places sur des niveaux diffrents. Le moteur retourne toujours la valeur de plus haute prcdence pour la valeur courante . Si la valeur

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

19

dun niveau suprieur disparat, la proprit prend immdiatement la valeur du niveau juste en dessous. Il y a bien mmorisation de plusieurs valeurs distinctes pour une mme proprit, mais uniquement pour des valeurs places sur des niveaux hirarchiques diffrents. Au sein dun mme niveau toute nouvelle valeur remplace la prcdente sans aucun effet mmoire. Un binding tant considr comme de mme niveau hirarchique quune valeur locale modifier cette dernire tue le binding sans espoir de retour en arrire. Alors que si, pendant que le binding est en place, nous jouons une animation qui ensuite sarrte, la valeur affiche reviendra { celle du binding Rgles de prcdences Les rgles qui ont t poses sont assez logiques fonctionnellement parlant et ne sont pas trs difficiles mmoriser mais quand on entre dans les dtails il existe beaucoup plus de niveaux que ce que la documentation MSDN laisse croire de prime abord. Car en dehors des niveaux hirarchiques rels, qui sont peu nombreux, il existe des situations concurrentielles comme celle du binding que nous avons vue entre lesquelles il existe bien, dans la pratique, une hirarchie fonctionnelle. La hirarchie prsente ci-dessous tient ainsi compte la fois des niveaux officiels et des sous hirarchies pratiques . La position 1 correspondant la prcdence la plus haute. 1. 2. 3. 4. 5. 6. 7. 8. La valeur donne a une proprit par une animation active, ou bien une animation termine mais qui est en mode Hold (tenue de valeur). La valeur locale. La valeur provenant dun binding agissant sur la valeur locale (binding classique). La valeur issue dun template appliqu { lobjet. La valeur dun binding dun property Setter dfini { lintrieur dun style La valeur issue dun style. La valeur ambiante hrite de larbre visuel. La valeur par dfaut de la proprit elle-mme.

Comme on le voit ici, si les choses sont logiques, la multitude des niveaux rend malgr tout la matrise des valeurs dlicates dans une application relle ds lors que saisies manuelles, animations, styles et templates viennent sadditionner { la valeur par dfaut et { celle hrite de larbre visuel ! Lordre dans lequel la squence dattribution des valeurs sera joue aura aussi son importance. Pour rsumer, une valeur obtenue par binding est en ralit une valeur locale et possde le mme niveau de prcdence quune telle valeur. Le fait dutiliser SetValue ou de modifier la proprit autrement en lui donnant une nouvelle locale remplace et annule le binding en cours (qui est de mme niveau hirarchique). Cest pour cette raison que jai plac la vraie valeur locale un cran au dessus dans la hirarchie que la valeur obtenue par binding. Dans la pratique la valeur locale prend le dessus et annule le binding. En revanche cest parce que le binding est bien une valeur locale que fixer une nouvelle valeur locale annule totalement le binding. En revanche, les valeurs qui sont situes sur des niveaux hirarchiques diffrents peuvent coexister et un retour en arrire est toujours possible. Par exemple si un rectangle est rouge par une opration de binding sur une couleur ou une brosse et quune animation est lance

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

20

pour le rendre vert, en fin de celle-ci (si elle nest pas en mode Hold), le binding ne sera pas cass et le rectangle redeviendra rouge. Bien comprendre la prcdence des valeurs des proprits de dpendance est un prambule indispensable leur bonne utilisation. Et cela joue une grande importance dans certains bogues de binding, do ces explications.

La notion de DataContext
La notion de DataContext est directement et intimement lie celle de binding puisquelle permet de fixer une source globale (un objet, une liste) dans laquelle tous les bindings dfinis ensuite dans sa porte iront piocher les proprits pour se lier. Lutilisation dun DataContext nest pas obligatoire pour faire du binding, mais les avantages quil procure dans de nombreuses situations font quil est trs utilis.
DataContext est avant tout une proprit de la classe FrameworkElement dont

hritent tous les contrles. Sa valeur peut tre dfinie par code behind ou en Xaml. On peut mme dfinir un binding sur un DataContext en tant que proprit cible, les rgles de prcdences sappliquent aussi puisque DataContext est une proprit de dpendance.
DataContext accepte comme valeur un object. C'est--dire tout ce quon veut. Cette souplesse

peut tre source derreur. Accepter une object et non une classe prcise et ses descendants fait quil ne peut y avoir aucun contrle de type sur lobjet transmis au DataContext. Une proprit de type object est un peu lquivalent ct code behind des paramtres en chanes de caractres de Xaml, une grande souplesse mais aucun contrle { la compilation. Cest donc une source possible de bogues, derreurs diverses et varies qui ne pourront tre dtectes que par des tests systmatiques de lapplication en utilisation relle. Cest principalement pour attirer votre attention sur ces problmes potentiels que je vous parle du DataContext, le but nest pas de remplacer la documentation ou les articles sur le sujet que vous trouverez sur le Web. Le fait de faire pointer un DataContext sur un mauvais objet ne gnrera aucune erreur, et selon lutilisation qui est faite des bindings, il sera parfois trs difficile de voir quil y a eu confusion. Vigilance, toujours, donc Le DataContext permet doffrir une source cohrente contenant toutes les proprits ncessaires une interface visuelle ou une partie de celle-ci. Lutilisation du DataContext dans un tel cadre est la base de patterns comme Model-View-ViewModel. Cela justifiait aussi de laborder, mme brivement.

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

21

Les convertisseurs de valeur


Ils sont au cur du binding et il est impossible de parler de ce dernier en passant sous silence la notion de convertisseur. Tout au long de cet article je parle de convertisseurs, plusieurs fois jen utilise dans la mise en uvre des exemples. Il est donc important den comprendre lutilit et limplmentation. Dfinition Le binding permet de connecter deux proprits quelconques ensemble. Les types de ces proprits peuvent eux aussi tre quelconques et diffrents. Si le Framework possde des automatismes de conversion, ces derniers ne peuvent couvrir la totalit des besoins crs par le binding. Il est donc ncessaire doffrir un mcanisme permettant de convertir une valeur source en une autre valeur compatible avec le type de la cible du binding. Cest le rle des convertisseurs de valeur. Ils prennent une valeur dentre et la transforment pour quelle devienne une valeur acceptable par la cible en sortie. Le mcanisme complet supporte la conversion dans les deux sens mme si cette utilisation est assez rare. Scnario Supposons un rectangle pos sur une fiche ainsi quun Slider prenant les valeurs de 1 10. Imaginons que nous voulions que le rectangle soit cach (Visibility.Collapsed) lorsque la valeur du Slider est infrieure { 6 et quil soit affich dans le cas contraire (Visibility.Visible). Naturellement on ne souhaite pas grer cette situation { lancienne c'est--dire en programmant un gestionnaire dvnement sur le changement de valeur du Slider, code qui modifierait la visibilit du rectangle. Ce nest pas une question de mode, il sagit plutt de bonnes pratiques et de sparation forte entre code et interface visuelle. Limplmentation dun gestionnaire dvnement crera une dpendance forte entre code et visuel alors que limplmentation dun convertisseur autorisera une meilleure sparation ainsi quune rutilisation du code bien plus grande. Dans une vision plus moderne et plus conforme { lesprit de Xaml donc, nous souhaitons utiliser un binding entre la proprit Visibility du rectangle et la proprit Value du Slider. Seulement ces deux proprits ne sont pas compatibles entre elles. Aucun automatisme ne peut savoir partir de quelle valeur du Slider il faut considrer que le rectangle est visible ou non. Cest l{ quinterviennent les convertisseurs de valeur. Dans le cas prcis de notre exemple fictif du rectangle il faudra crire un convertisseur acceptant en entre un double (la valeur du Slider) et produire en sortie une valeur de type Visibility en respectant les contraintes indiques.

Rpertoire : Sample0 Projet ConverterSample

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

22

Ce genre de situation est trs frquent sous WPF et Silverlight et les projets de ce type possdent gnralement un rpertoire ddi contenant de nombreux convertisseurs. Implmentation Les convertisseurs de valeur sont des classes tout ce quil y a de plus basiques. Leur seule contrainte : implmenter linterface IValueConverter pour des bindings simples, ou IMultiValueConverter pour les bindings multiples. Ces interfaces exposent deux mthodes : Convert et ConvertBack. La premire est systmatiquement utilise, la seconde plus rarement (certaines transformations ntant pas facilement rversibles et de nombreux bindings ne sont pas double sens). Voici un exemple typique de convertisseur :
class BoolToVisibilityConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (targetType != typeof(Visibility)) return null; bool v; if (value is bool?) v = ((bool?)value).HasValue ? ((bool?)value).Value : false; else if (value is bool) v = (bool)value; else v = false; return v ? Visibility.Visible : Visibility.Collapsed; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { if (targetType != typeof(bool) && targetType != typeof(bool?)) return null; if (!(value is Visibility)) return false; return (Visibility)value == Visibility.Visible ? true : false; } }

Le code ci-dessus sait convertir un boolen en une valeur Visibility. Si le boolen est vrai la visibilit retourne sera Visible, sinon Collapsed. On remarque que la conversion inverse a t programme dabord { titre dexemple et car il nest pas insens de convertir une visibilit en boolen (mme si le caractre binaire du boolen oblige rduire les trois tats de la visibilit visible, hidden, collapsed deux tats, visible ou collapsed). Le convertisseur reoit dans ses mthodes une valeur convertir (le premier paramtre) sous la forme dun object, il reoit aussi le type de la cible, un ventuel paramtre et une culture optionnelle. Cette dernire permet de forcer la prise en charge dune culture donne indpendamment de celle de lapplication. Le cas se rencontre assez rarement. Le paramtre optionnel est un object, on peut ainsi utiliser un paramtrage aussi complexe que ncessaire en passant une instance de classe contenant ces derniers.

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

23

Utilisation Une fois cods en C# (ou autre), les convertisseurs sont utiliss au sein des balises de binding de Xaml. Instanciation Pour utiliser un convertisseur il faut quune instance existe, ce qui parat logique. Il existe plusieurs faons de crer cette dernire. La plus commune consiste crer une ressource dans la fentre en cours. Si le convertisseur est utilisable en de nombreux endroits de lapplication certains dveloppeurs prfrent alors le placer dans App.xaml. Aprs avoir dclar le namespace on trouvera une dclaration de ce type dans les ressources :
<Window.Resources> <conv:BoolToVisibilityConverter x:Key="BoolConv" /> </Window.Resources>

Le namespace est dclar comme suit :


xmlns:conv="clr-namespace:ConverterSample.Converters"

Bien entendu le nom exact du namespace dpend de votre application. Le raccourci conv est aussi purement arbitraire. Toutefois il est judicieux de placer tous les convertisseurs dans un mme namespace et de les dclarer avec un raccourci propre plutt que dutiliser le namespace de lapplication comme un fourre-tout. Invocation On invoque un convertisseur au sein dun binding. Il est difficile de vous prsenter un binding sans explication mais ltude de la nature et de la syntaxe de tous les types de bindings est lun des sujets principaux de cet article, vous trouverez donc toutes les explications dans le prsent document. Pour linstant concentrons-nous sur le convertisseur. Et pour illustrer le propos regardons une capture du projet ConverterSample fourni avec larticle :

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

24

Figure 5 - Convertisseur de valeur en action

Dans cette application nous trouvons des carrs de couleur et des CheckBox permettant de les afficher ou de les cacher. Lexemple qui nous concerne pour linstant est celui du premier carr (bleu). Le code Xaml de sa dclaration est le suivant :
<Rectangle Height="52" HorizontalAlignment="Left" Margin="16,18,0,0" Name="rectangle1" Stroke="Black" VerticalAlignment="Top" Width="55" Fill="Azure" Visibility="{Binding ElementName=checkBox1, Path=IsChecked, Converter={StaticResource BoolConv}}"/>

La partie importante est celle qui dclare le binding sur la proprit Visibility du Rectangle. Elle est lie la checkBox1, sur sa proprit IsChecked. Comme les boolens ne sont pas directement compatibles avec le type Visibility (une numration de mme nom que la proprit) il est ncessaire de fournir un convertisseur. Cest ce que nous faisons en indiquant linstance du convertisseur qui a t dclar dans les ressources de la fentre sous le nom de BoolConv. Le code du convertisseur est celui donn en exemple un peu plus haut. Bonnes pratiques Il ny a que rarement des rgles absolues en informatique, surtout dans des environnements aussi riches que WPF ou Silverlight. Il ne peut y avoir que des conseils, des bonnes pratiques prouves par lexprience. Concernant les convertisseurs les questions qui se posent sont les suivantes : O faut-il les dclarer ? O faut-il les instancier ?

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

25

A la premire question nous avons dj rpondu en proposant de tous les placer dans un sous rpertoire ddi du projet et dans un espace de nom qui leur est propre. Dans certains projets il peut mme savrer intressant de les regrouper dans un mme projet gr part de type Dll, assemblage que les autres applications pourront ensuite partager. La seconde question est moins vidente trancher. Les convertisseurs ne consomment pas beaucoup de mmoire, mais si on en utilise beaucoup il nest peut tre pas forcment utile de tous les placer dans App.xaml (leur cycle de vie devient alors celui de lapplication). Et puis App.xaml peut trs vite devenir un fatras inextricable si on ny prend garde. Lexemple que nous venons dtudier cre linstance sous la forme dune ressource de la fentre. Cette mthode a lavantage de localiser les convertisseurs et de ninstancier que ceux qui sont exploit par la fentre. Lorsquelle disparatra le ou les convertisseurs utiliss seront librs. Toutefois sil sagit de la fentre principale de lapplication ou dune fentre (ou un UserControl sous Silverlight) qui nest jamais dtruite, lavantage du cycle de vie localis devient caduque. Ainsi, certains dveloppeurs prfrent crer une classe statique regroupant tous les convertisseurs. Ces derniers sont instancis systmatiquement ou bien la premire utilisation (ce qui est plus conome surtout sil y a beaucoup de convertisseurs et quils ne sont pas forcment tous exploits). Cette stratgie simplmente comme suit :
static class Converters { private static BoolToVisibilityConverter boolToVisibility; public static BoolToVisibilityConverter BoolToVisibility { get { if (boolToVisibility == null) boolToVisibility = new BoolToVisibilityConverter(); return boolToVisibility; } } }

La classe statique Converters regroupe tous les convertisseurs sous la forme de proprits statiques. Les instances sont cres une fois pour toute mais uniquement lors de la premire utilisation. Les convertisseurs inutiliss ne sont pas crs inutilement. Lapplication exemple ne comportant quun seul convertisseur cest bien entendu le principe quil faut retenir et non son exploitation dans ce cadre prcis. Lorsque les convertisseurs sont runis dans une classe statique, leur utilisation dans les bindings est lgrement diffrente. La dclaration du namespace ne change pas (cest un choix dans lapplication exemple), et le binding devient ainsi :
<Rectangle Fill="BurlyWood" HorizontalAlignment="Left" Margin="15,84,0,0" Name="rectangle2" Stroke="Black" Width="55" Height="52" VerticalAlignment="Top"

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

26

Visibility="{Binding ElementName=checkBox2, Path=IsChecked, Converter={x:Static conv:Converters.BoolToVisibility}}" />

On notera la syntaxe particulire permettant de spcifier lutilisation dune classe et dune proprit statiques. Dans lapplication exemple il sagit du second carr, le marron. Enfin, dautres dveloppeurs prfrent ne pas utiliser la stratgie de la classe statique et mettent en uvre la pattern singleton dans leurs convertisseurs. Pour illustrer ce cas (le troisime carr de lapplication exemple, couleur lavande) nous allons construire un convertisseur implmentant la pattern singleton partir de la classe dj utilise :
class BoolToVisibilitySingletonConverter : BoolToVisibilityConverter { private BoolToVisibilitySingletonConverter() { } private static readonly BoolToVisibilitySingletonConverter instance = new BoolToVisibilitySingletonConverter(); public static BoolToVisibilitySingletonConverter Instance { get { return instance;} } }

La nouvelle classe hrite du convertisseur utilis prcdemment. Cela par pur souci pratique dans la dmonstration, dans la ralit cest bien le premier convertisseur qui aurait t demble implment sous la forme dun singleton si tel tait le choix. Lapplication exemple gre trois stratgies en mme temps et cette astuce vite de dupliquer le code ou de crer trois projets distincts. La faon dont la pattern singleton est implmente est classique : le constructeur de la classe est rendu priv pour interdire toute instanciation directe, et une proprit statique Instance est propose pour accder au convertisseur. On notera quon pourrait ici aussi implmenter linstanciation au premier appel plutt quune instanciation systmatique. Lorsque le convertisseur est implment sous la forme dun singleton, son utilisation en Xaml est trs proche de la version prcdente (celui de la classe statique regroupant tous les convertisseurs). Ainsi, le troisime carr de couleur lavande est cod de cette faon :
<Rectangle Fill="Lavender" HorizontalAlignment="Left" Margin="15,149,0,0" Name="rectangle3" Stroke="Black" Width="55" Height="52" VerticalAlignment="Top" Visibility="{Binding ElementName=checkBox3, Path=IsChecked, Converter={x:Static conv:BoolToVisibilitySingletonConverter.Instance}}" />

Pour rsumer Les convertisseurs sont des briques indissociables du binding. Bien comprendre leur fonctionnement, leur implmentation et choisir correctement la stratgie dinstanciation peut avoir un effet visible sur certaines applications. Nous aurons loccasion de revenir sur leur rle plusieurs fois encore dans cet article.

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

27

Les dangers du Binding

e ne reprendrai pas le dtail de mon billet cit en introduction de larticle, mais pour fixer les choses je rappellerai deux points principaux des problmes soulevs par le Binding tel quil a t implment dans Xaml et quillustre { merveille le petit exemple de code du paragraphe Le Binding , Dclaration page 10 : 1- Mme dans sa version C#, la dfinition dun binding repose sur le passage dun nom de proprit sous forme de chane de caractres non contrle la compilation. 2- Dans sa version totalement Xaml, et mme sur un exemple aussi simple que celui de lhorloge, outre le problme prcdent, on voit apparaitre une syntaxe alambique pleine daccolades amricaines, de virgules et darguments bien difficiles { retenir dautant plus que tout cela change selon le contexte comme nous le verrons.

Des chanes non contrles


Dans le premier exemple (dfinition du binding par code C#) on voit clairement que lors de la cration de linstance de la classe de binding nous passons la chane TimeOfDay . Aucun contrle nest effectu et aucune erreur dexcution ne sera leve si cette chaine nest pas valide ! Oublions une majuscule ou ajoutons une lettre et plus rien ne marchera. Dans le projet exemple changez dans la dfinition du binding Xaml une lettre TimeOfDay, ajoutez un s la fin par exemple. Relancez lapplication La TextBox sera vide, cest tout. Ici le problme est visible comme le nez au milieu de la figure, il ny a que deux TextBox (la fixe, et la seconde qui volue dans le temps). Il est facile de voir quil y a un problme. Imaginez seulement un instant les ravages de ce type de bug dans une application relle de 200 crans, contenant des milliers de contrles et des codes Xaml de plusieurs centaines de lignes (donc incontrlables { lil) Ce problme existe dailleurs { dautres endroits dans le Framework, notamment dans une fonctionnalit de base : INotifyPropertyChanged qui rclame le passage du nom de la proprit modifie sous la forme de chane de caractres. Jai vu de trs nombreux codes montrer des dysfonctionnements trs difficiles dceler uniquement cause de cette particularit (toujours pareil, on refactore en changeant les noms des proprits mais on oublie, ce qui est humain, de mettre jour la chane de caractres utilise par lvnement PropertyChanged). Ces trous dans la scurit du code au sein dun difice aussi bien ficel que le Framework .NET est comme une planche savonneuse sur laquelle le dveloppeur Silverlight et WPF devra marcher toute la journe sans se casser la figure. Choix conceptuel tonnant et pour le moins risqu. Il existe malgr tout des moyens de contrler les erreurs de binding, nous verrons cela plus loin au chapitre des solutions.

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

28

Un langage dans le langage


Ce nest plus un nom de proprit qui est pass en chane de caractre mais cest tout un mini langage de programmation avec imbrication de chanes et daccolades que nous rserve la syntaxe du Binding ! Ici la planche est toujours savonneuse, mais sur les deux faces, et en plus vous avez les yeux bands. Difficile de rester debout ! Plus srieusement, on comprend la tentation dutiliser des chanes de caractres interprtes pour tendre la puissance du langage Xaml tout en lui conservant sa structure assez simple de fichier SGML. Malgr la richesse du concept (assez ancien maintenant) ayant donn naissance des langages comme Html ou Xml et donc Xaml, il faut avouer que SGML na peut-tre pas t pens pour tant dextensions et que Xaml flirte certainement avec les limites conceptuelles de ce format. Toutefois il existe une rponse ce problme ponctuel : comprendre et connatre la syntaxe du Binding dans ces diffrentes tournures. Cest ce que nous verrons au chapitre des solutions.

On fait quoi ?
La plus belle des filles (ou le plus beau des hommes, ne soyons pas sexistes) finira toujours par rvler quelques petits dfauts cachs Si on est amoureux on fermera les yeux et on sadaptera. Xaml nest pas parfait, il faut lavouer, mais une fois ce constat pos, que pouvons-nous faire concrtement ? Comme nous sommes anims par des sentiments purs et passionns, nous allons tout simplement tenter de composer avec ses faiblesses. Et des moyens existent. Cest ce que nous allons voir maintenant.

Dboguer le Binding
Vigilance
Rgle dor, la vigilance. Comme il ne sagit pas dabandonner le binding (pas plus que INotifyPropertyChanged), il va falloir fournir un effort constant de vigilance. Ne pas hsiter vrifier le code Xaml mme quand il est verbeux. Les utilisateurs de Expression Blend sont particulirement concerns car lenvironnement a t entirement conu dans un but : crire du Xaml votre place. De fait on peut travailler des heures sur un projet complexe sans mme jamais voir une ligne de Xaml. Cest le gros avantage de Blend, notamment parce quil permet { des infographistes ou des intgrateurs dviter le contact un peu rugueux avec Xaml. Mais sous Blend aussi on peut voir le code Xaml et agir sur lui, et bien souvent il ne faut pas sen priver !

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

29

Une code Xaml court


Le meilleur code Xaml est le plus court possible Dans ce ddale de balises, le seul moyen de conserver une possibilit humaine de contrle est encore de se dbrouiller pour crer des fichiers Xaml de petite taille. Pour cela plusieurs moyens : Crer des UserControl ayant des rles clairs et prcis, quitte imbriquer plusieurs UserControl pour en crer un, plus gros, assurant la totalit de la fonctionnalit. Crer des dictionnaires de ressources pour chaque ressource. Un dictionnaire pour la palette de couleurs et les brosses, un autre pour le template du CheckBox, un autre pour le template du RadioButton, etc. Eviter les gros fichiers skins incontrlables humainement. Si vous travaillez sous Blend, nhsitez pas { revisiter la balise du contrle que vous venez de toucher : supprimer les numriques ayant des tonnes de chiffres aprs la virgule. Une position par exemple (ou une Margin) na pas besoin de 15 dcimales, sauf cas exceptionnel qui reste trouver. Pourtant ce sont des Double qui sont utiliss et souvent force de manipulation ces nombres possdent une partie fractionnaire inutile qui brouille la lisibilit.

Refactoring sous contrle


Tout refactoring, notamment un changement de nom de classe ou de proprit doit tre suivi dune vrification manuelle. Pour cela je vous incite toujours effectuer une simple recherche du nom original dans toute la solution. On est parfois surpris de dcouvrir quil se cache des utilisations quon ne souponnait pas, surtout dans de gros logiciels crits { plusieurs !

Utiliser des outils intelligents


Visual Studio est certainement lEDI le mieux conu, mais il y a de la place pour des amliorations. Vous pouvez ainsi utiliser des outils comme Resharper (voir adresse dans les rfrences) qui proposent un degr dintelligence suprieur au refactoring de base de Visual Studio, notamment en proposant de chercher dans les chanes et mme dans les commentaires.

Utiliser Expression Blend


Cest tout bte, mais je vois encore beaucoup de dveloppeurs qui font du Silverlight ou du WPF sans utiliser Blend ! Cela mapparat impossible pour crer des compositions visuelles et des animations dignes de ce nom. Blend simplifie aussi beaucoup le binding en crivant le code Xaml { votre place Le meilleur moyen de produire un code de binding sans erreur est encore deffectuer les liens sous Blend. VS 2010 apporte nanmoins quelques plus non ngligeables par rapport la version 2008. Les autres conseils sappliquent malgr tout en cas de refactoring ({ faire sous VS avec Resharper ou quivalent) ou en cas de modification dun binding. Utiliser Blend nexonre pas totalement le dveloppeur dune bonne connaissance de Xaml ni mme dutiliser Visual Studio qui propose des aides dcriture et de contrle du code (Xaml et C#) bien suprieures.

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

30

Vrifier les erreurs de binding dans la fentre de sortie


Je vous expliquais quune erreur dans les chanes de caractres dfinissant un binding ne gnrait pas derreur { lexcution. Cest vrai du point de vue du logiciel qui tourne, mais il y a bien des erreurs qui sont souleves Elles ne sont pas fatales, ne soulvent pas dexceptions quon peut grer avec un Try/Catch, elles se cachent dans la fentre de sortie de Visual Studio ! Hlas cette fentre est un peu un fourre-tout qui se remplit de messages tout au long de lexcution dune application sous dbogueur. Mais rien ninterdit de faire un copier-coller de son contenu dans le bloc-notes pour y chercher certains messages particuliers grce un simple Ctrl-F Car dans lexemple de lhorloge, si au lieu dun binding avec TimeOfDay jcris TimeOfDays , si aucune erreur dexcution nest leve, dans la trace de sortie on peut trouver le message suivant :
System.Windows.Data Error: 39 : BindingExpression path error: 'TimeOfDays' property not found on 'object' ''DateTime' (HashCode=-2099349868)'. BindingExpression:Path=TimeOfDays; DataItem='DateTime' (HashCode=-2099349868); target element is 'TextBox' (Name='MaTextBox'); target property is 'Text' (type 'String')

Toujours aussi droutant L{ o on croyait tre tomb dans un no mans land on se retrouve avec des messages derreur dune prcision diabolique ! Nous connaissons ici le type derreur, cest { lintrieur dun BindingExpression, dans son Path, la proprit TimeOfDays nest pas trouve sur lobjet DateTime. De fait la cible qui est un TextBox portant le nom MaTextBox ne verra pas sa proprit Text lie la source. Vous comprenez maintenant quun simple Chercher dans toute la fentre de sortie de phrases comme System.Windows.Data Error ou BindingExpression path error peut vous permettre de relever sinon toutes au moins de nombreuses erreurs de binding causes par une chaine de caractres dfaillante mme au sein dune grosse application.

Crer un fichier des erreurs de Binding


Lapproche prcdente, base sur un copier-coller de la fentre de sortie dans le bloc-notes et assortie dune recherche peut tre largement amliore sous WPF depuis les versions 3.0 et 3.5. Le systme de Trace Source repose sur le fichier de configuration de lapplication (App.config) par lajout de certaines balises. Voici un exemple dun tel fichier modifi pour assurer lenregistrement de la fentre de sortie dans un fichier texte (voir le projet exemple fourni) :

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

31

<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.diagnostics> <sources> <source name="System.Windows.Data" switchName="SourceSwitch" > <listeners> <add name="textListener" /> </listeners> </source> </sources> <switches> <add name="SourceSwitch" value="All" /> </switches> <sharedListeners> <add name="textListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="BindingDebugTrace.txt" /> </sharedListeners> <trace autoflush="true" indentsize="4"></trace> </system.diagnostics> </configuration>

La partie en gras est la configuration du Source Trace (lessentiel du code ici). On peut y fixer des filtres, par exemple ici le filtrage se fait sur les messages de System.Windows.Data. Si vous souhaitez dboguer des animations cest plutt lassemblage System.Windows.Media.Animation que vous indiquerez par exemple. Cela vite dtre noy dans des tas de messages qui pourraient tre gnant pour voir les erreurs recherches. Comme nous voulons voir tous les messages derreur nous indiquons All dans la section des switches. Les valeurs possibles sont Off, Error, Warning. Je souhaite que les erreurs soient crites dans un fichier texte BindingErrorTrace.txt , cest ce qui est indiqu dans la section sharedisteners. On pourrait choisir dautres Listeners, par exemple ConsoleTraceListener qui affiche les messages la console, ou bien choisir un format de sortie de type XML ce qui en faciliter le traitement automatiquement par une moulinette que vous crirez pour loccasion Vous pouvez vous rfrer { lexcellent billet de Mike Hillbergs Trace sources in WPF pour avoir plus de prcision sur ce mcanisme de log intgr et les subtilits de son paramtrage (voir ladresse dans la liste des rfrences en dbut darticle). En relanant lapplication (toujours avec lerreur du s ajout TimeOfDay dans le binding en C#), nous obtenons dans le folder bin\debug le fichier texte attendu dont le contenu est :
System.Windows.Data Error: 39 : BindingExpression path error: 'TimeOfDays' property not found on 'object' ''DateTime' (HashCode=1822811999)'. BindingExpression:Path=TimeOfDays; DataItem='DateTime' (HashCode=1822811999); target element is 'TextBox' (Name='MaTextBox'); target property is 'Text' (type 'String') System.Windows.Data Information: 19 : BindingExpression cannot retrieve value due to missing information. BindingExpression:Path=TimeOfDays; DataItem='DateTime'

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

32

(HashCode=1822811999); target element is 'TextBox' (Name='MaTextBox'); target property is 'Text' (type 'String') System.Windows.Data Information: 20 : BindingExpression cannot retrieve value from null data item. This could happen when binding is detached or when binding to a Nullable type that has no value. BindingExpression:Path=TimeOfDays; DataItem='DateTime' (HashCode=1822811999); target element is 'TextBox' (Name='MaTextBox'); target property is 'Text' (type 'String') System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=TimeOfDays; DataItem='DateTime' (HashCode=1822811999); target element is 'TextBox' (Name='MaTextBox'); target property is 'Text' (type 'String')

Comme nous avons demand tous les niveaux de message (All), la trace est mme plus complte que dans la fentre de sortie de Visual Studio. Seul inconvnient de cette solution cest quelle ne fonctionne quavec WPF pour des tas de raisons videntes (par exemple o serait crit le fichier de trace sur la machine hte alors que les droits pour une telle action nexistent pas pour une application Web ?). Il existe des extensions au systme de Trace Source dans WPF 3.5 notamment pour dboguer des situations encore plus dlicates (cas dun binding qui fonctionne, mais qui dpend dune valeur qui est longue obtenir depuis un Web service, une base de donnes lobjet bind pouvant rester alors vide). Je vous renvoie un autre billet tout aussi intressant que le prcdent, How can I debug WPF bindings ? de Bea Stollnitz (voir les rfrences en dbut darticle).

La feinte du convertisseur inutile


Je tiens cette ide de la mme Bea Stollnitz, ide qui se rsume cela : puisque Xaml est un langage qui ne dispose pas de dbogueur et que le binding est souvent dfini dans ce dernier, le meilleur moyen pour inspecter un binding rcalcitrant est de le forcer revenir dans le code C# o il sera possible de placer un point darrt pour inspecter les valeurs Bien entendu il nest pas question ici de supprimer le binding en Xaml pour le remplacer par un quivalent en C#, cela naura aucun sens. Le binding Xaml reste sa place dans ses balises. Et pour le forcer { faire un dtour par C# il suffit dadjoindre { la dfinition du binding lutilisation dun convertisseur. Ce dernier ne servira rien, donc un code minimum, mais sera bien suffisant pour placer un point darrt. La feinte est intressante, nest-il pas ? Voici le code du convertisseur de dbogue :

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

33

public class DebuggingConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return value; // Ajouter le point darrt ici ! } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException("mthode non implmente"); } }

Pour ajouter la prise en charge du convertisseur dans un binding il faut connatre les mandres de la syntaxe du binding que nous verrons la section suivante. Voici un exemple avec le TextBox du projet de dmo fourni avec cet article : Dans les ressources de la Window en cours :
<local:DebuggingConverter x:Key="debugConverter" />

Puis lajout du convertisseur dans le binding du TextBox :


<TextBox Text="{Binding Source={StaticResource Horloge}, Path=Heure, Mode=OneWay, Converter={StaticResource debugConverter}}" Name="MaTextBox2" />

Ne reste plus qu{ placer le point darrt sur la ligne indique dans le convertisseur et laffaire est joue, vous avez accs tout ce qui est ncessaire pour dboguer le binding posant problme au moment prcis o la valeur est modifie. Avantage : la technique est utilisable avec Silverlight sous dbogueur Visual Studio.

Quelques outils supplmentaires


Vous retrouverez les liens vers les outils prsents ici dans la partie Rfrences en dbut darticle. Bien que tous ces outils de dbogue ne soient pas exclusivement destins au binding, ils vous seront certainement trs utile si vous tombez sur un bug rcalcitrant Spy++ Il sagit dun utilitaire de dbogue de Microsoft qui permet dobtenir une vue dtaille des processus, des threads, des fentres et des messages Windows. Cest un outil Win32, plutt utilis par les dveloppeurs C++ mais qui peut savrer utile dans certains cas, notamment lors dappel de code non manag. ManagedSpy Il sagit dun quivalent manag de Spy de chez Microsoft aussi. Etudi pour le dbogue dapplications manages cest un outil peu connu qui peut savrer trs utile. De plus il est fourni avec le code source, autant de sa partie c++ que de sa partie manage en C#.

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

34

Snoop Snoop est un quivalent de Spy++ et de ManagedSpy mais en plus convivial dvelopp par Pete Blois. Cest une application WPF fournie en mode source, donc trs instructif en plus dtre utile ! Mole Aprs les espions (Spy & Co) voici la taupe ! Conu par les mmes personnes que les clbres Power Toys, Mole est un dbogueur qui fonctionne aussi bien avec WPF que les Windows Forms ou mme ASP.NET. Mole nest pas indpendant de Visual Studio, cest un plugin qui agit comme un viewer personnalis. Lutilitaire est fourni en binaire et en source. Reflector On ne prsente plus cet utilitaire qui permet notamment de dcompiler un excutable ou une librairie, ce qui savre trs utile notamment avec le Framework Silverlight pour vrifier certaines diffrences avec WPF et regarder limplmentation de certaines mthodes. Bien que rachet par Red Gates (qui produit aussi le profiler Ants et toute une flope doutils orients base SQL) il existe toujours une version gratuite qui dsormais peut tre appele directement depuis lEDI de Visual Studio. Vos neurones On les oublie parfois en se jetant sur des outils de dbogue, mme ceux de Visual Studio, je vois souvent des dveloppeurs perdre beaucoup de temps et au final ne pas trouver ce quils cherchent. Noubliez jamais que le meilleur outil de dbogue du march vous le possdez dj{ : ce sont vos neurones. Jamais aucun dsassembleur ni espion de code narrivera { la cheville de ce quune poigne de neurones bien rveills peuvent faire pour dcouvrir et radiquer un bug !

Les syntaxes du Binding


Je ne ferai pas le tour des moyens de dclarer du Binding par code, les problmatiques sont diffrentes, et seules les chanes de caractres non contrles la compilation doivent rclamer de votre part une grande vigilance. De plus il est assez rare de dclarer un binding en code behind. En revanche les syntaxes du Binding lorsquil est dclar dans le code Xaml mritent quelques claircissements. Un peu sotrique et changeante selon les cas, donc difficile mmoriser, la syntaxe du binding est une source derreurs qui pour beaucoup ne seront pas dtectes (pas mme derreur dclenche { lexcution, sauf en utilisant les traces expliques plus haut). De plus, tirer partie de toutes les subtilits de cette syntaxe rclame de la matriser, mme un outil comme Blend ne prend pas toutes les facettes en charge ds lors quon sort des sentiers battus ou que lon cherche loptimisation.

Le binding simple
Le plus simple des binding est celui qui rfrence directement le DataContext courant.

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

35

Binding direct
Exemple : Content="{Binding}"

Ici la proprit Content dun label est directement lie au DataContext local. Pour mettre en uvre un binding aussi simple, nous plaons un Label dans une Grid. La proprit DataContext de cette dernire rfrence une ressource statique appele Titre.

Figure 6 - Binding direct

La ressource est dfinie comme suit :


<Window.Resources> <System:String x:Key="Title">Exemple 2</System:String> </Window.Resources>

Cest un moyen trs simple de dclarer des chanes, des constantes numriques quon regroupe dans les ressources de la fentre en cours ou dans un dictionnaire (App.xaml ou un dictionnaire externe).

Rpertoire : Sample2 Projet SimpleBinding

La grille et son label sont dfinis comme suit :


<Grid Name="GridTitle" DataContext="{StaticResource Title}"> <Label Margin="0" Name="label1" Content="{Binding}"/> </Grid>

Jai volontairement supprim tout le code de prsentation (marges, taille, position) pour ne garder que le code Xaml fonctionnel. Vous trouverez le code complet de cet exemple dans le projet SimpleBinding fourni avec larticle. Binding sur une proprit
Exemple : Content="{Binding Now}"

Ici la proprit Content dun Label est lie au DataContext courant, sur sa proprit Now. Le DataContext est une instance de DateTime.

Figure 7 - binding sur une proprit

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

36

Pour raliser cet exemple nous avons besoin dune autre ressource locale de type DateTime :
<Window.Resources> <System:DateTime x:Key="Time" /> </Window.Resources>

Le Label est plac dans une grille dont le DataContext pointe la ressource ainsi dfinie. La proprit Content du Label est alors lie par binding la proprit Now du contexte courant :
<Grid Name="GridHeure" DataContext="{StaticResource Time}"> <Label Name="label2" Content="{Binding Now}" /> </Grid>

Comme pour lexemple prcdent jai supprim le code de prsentation des balises. Vous noterez que cette dmonstration rapide fonctionne trs bien en design sous Visual Studio et que la date et lheure saffichent correctement. Mais si vous tentez de lexcuter une erreur se produira car DateTime na pas de constructeur par dfaut4. Pour faire fonctionner lexemple au runtime il est ncessaire dcrire notre propre classe DateTime possdant ainsi un constructeur par dfaut. Cest ce que vous trouverez dans le projet exemple SimpleBinding qui contient la classe suivante utilise en place et lieu de DateTime dans la balise de cration de la ressource :
public class MyDateTime { public DateTime Now { get { return DateTime.Now; } } }

Binding sur une sous-proprit du contexte Dans la mme logique il est possible datteindre une proprit dune proprit du DataContext.
Exemple : Content="{Binding Now.Kind}"

En reprenant lexemple ci-dessus il est possible daccder { lune des proprits de Now du DateTime (enfin de notre MyDateTime) cr en ressource. Kind affiche le type de date/heure pris en compte (ici le texte Local sera affich).

Figure 8 - Accs une sous proprit du DataContext

Je reste tonn que cela passe en design. La raison mchappe. Si un GL (Gentil Lecteur) connait la raison quil me la communique, je la publierai sur Dot.Blog.

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

37

LElement Binding
Exemple : Content="{Binding ElementName=slider1, Path=Value}"

LElement Binding consiste { pouvoir lier un lment dinterface { un autre directement. Ajout dans Silverlight 3, WPF proposait dj ce procd trs pratique.

Figure 9 - Element Binding

Lexemple classique consiste montrer comment un Slider est li un Label pour afficher la valeur courante. Cest ce que prsente la figure ci-dessus. Laffichage direct dune valeur de type Double nest gnralement pas satisfaisant, les nombreuses dcimales qui apparaissent ne sont que rarement dsires (en tout cas laffichage) et peuvent ruiner la mise en page. Dans lexemple fourni (et sur la figure ci-dessus) les valeurs affiches sont des entiers. Cela nest hlas pas le comportement par dfaut Pour arriver ce rsultat il est ncessaire dutiliser un convertisseur de valeur. Convertisseurs de valeur Le propos de cet article est le binding, si nous entrons dans les dtails de tout ce qui peut tourner autour de cette technique ce long article sera trs vite un livre lui tout seul ! Toutefois les convertisseurs de valeur entrant dans la syntaxe du binding il est ncessaire den dire quelques mots, les plus curieux pourront chercher sur le Web les documents qui prsentent en dtail la technique et ses variantes de programmation. Le Binding permet de relier tout et nimporte quoi ensemble. Cest presque magique jusquau moment o lon comprend que tous ces types incompatibles entre eux sont rendus dociles grce aux convertisseurs implicites implments (de diverses faons) dans chaque classe. Toutefois ces convertisseurs ne sont parfois pas suffisants. Dans lexemple prcdent il sagit de transformer un double en entier pour obtenir un affichage plus sobre. Sagissant dun binding nous navons pas de moyen de forcer le transtypage comme nous le ferions par code. Dans dautres circonstances il sera ncessaire daller plus loin dans ladaptation des donnes utilises dans un binding. On peut fort bien imaginer une classe possdant une proprit indiquant un niveau dalerte sous la forme dune numration (par exemple Ok, Attention, Danger) et vouloir que cette information soit reprsente graphiquement par un contrle dont la couleur traduit le niveau dalerte (vert, jaune, rouge par exemple). Les systmes de conversion implicites du Framework ne peuvent plus rien ici, les types sont vraiment trop loigns loin de lautre (une numration et une couleur ou une brosse) et la

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

38

conversion rclame une interprtation (le code couleur ici) qui ne peut tre automatise. Un humain est oblig de choisir quelle couleur reprsentera quelle valeur de lnumration. Bref, dans tous ces cas il est ncessaire de convertir les donnes dun binding pour les rendre compatibles entre elles. La conversion peut tre sens unique ou double sens. Pour ce faire il faut crer un convertisseur de valeur. Il sagit dune classe supportant linterface IValueConverter. Dans lexemple du Slider le convertisseur est minimal :
[ValueConversion(typeof(double), typeof(int))] public class DoubleToIntConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var d = (double)value; return (int) d; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }

Ce convertisseur ne marche que dans un seul sens (ConvertBack nest pas implment) et il ne fait que transtyper un double en entier. Pour lutiliser nous devons le dclarer dans les ressources :
<Window.Resources> <local:DoubleToIntConverter x:Key="DoubleConverter"/> </Window.Resources>

Ensuite, le binding du Label de lexemple prcdent sera complt de la faon suivante :


Content="{Binding ElementName=slider1, Path=Value, Converter={StaticResource DoubleConverter}}"

Le paramtre Converter du binding est li la ressource statique que nous venons de crer. Ainsi, les valeurs en provenance du Slider seront passes par la moulinette du convertisseur avant darriver dans la proprit Content du Label. Bien entendu les convertisseurs de valeur sont utilisables dans tous les types de binding, lElement Binding ntant quun exemple. Paramtres de conversion Comme vous lavez certainement remarqu dans la dclaration du convertisseur ci-dessus, les deux mthodes possdent un paramtre appel parameter de type object. Il sagit dun paramtre optionnel qui peut tre pass au convertisseur pour en modifier le comportement.

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

39

Comme il sagit dun object, il est donc possible de passer des paramtres trs complexes (puisquon peut ainsi passer une instance dune classe comportant autant de proprits que ncessaire pour le paramtrage vis). Pour lexemple nous reprendrons le projet de lhorloge (WpfMiniBinding). Comme nous lavons vu lheure affiche par lhorloge est le rsultat dun appel { ToString(), c'est--dire un formatage standard possdant notamment de nombreux chiffres inutiles (en gnral) pour les millisecondes. Comment faire si nous souhaitons afficher uniquement lheure, sans les millisecondes ? Et comment ne pas rcrire des tas de convertisseurs pour les fois o nous souhaiterons afficher uniquement le jour, ou lanne ou tout autre formatage dune date ? Le plus simple est de crer un convertisseur de valeur acceptant un paramtre qui sera ici la chaine de format. Un tel code est trs simple :
public class DateConverter : IValueConverter { public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture) { try { var format = (string) parameter; if (string.IsNullOrEmpty(format)) return value.ToString(); var d = DateTime.Parse(value.ToString()); return d.ToString(format); } catch (Exception ex) { throw new Exception("Paramtre de formatage invalide." +ex.Message); } } public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } }

Il suffit ainsi dexploiter le paramtre parameter de la mthode Convert (ou ConvertBack si elle tait implmente). Le convertisseur est instanci dans les ressources de la fentre en cours (il pourrait tre plac ailleurs, dans App.xaml par exemple) :
<Window.Resources> <local:DateConverter x:Key="DateConverter" /> </Window.Resources>

La dfinition du binding de la TextBox devient ainsi :

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

40

<TextBox Text="{Binding Source={StaticResource Horloge}, Path=Heure, Mode=OneWay, Converter={StaticResource DateConverter}, ConverterParameter='HH:mm:ss'}" Name="MaTextBox2" />

La balise de binding se complexifie singulirement, mais une fois le convertisseur crit, il est vrai quil ny a plus besoin de code behind pour afficher des dates formates selon nos souhaits partout o des dates apparaissent dans un binding. Au final il sagit dune simplification De toute faon deux coles semblent tre nes et se renforcer dans leur spcificit de jour en jour : celle des dveloppeurs qui font le maximum en Xaml sans code , et ceux qui pensent que Xaml doit rester un langage de dfinition dinterface et que toute logique doit tre programme en code. Il y a toujours certains indcis qui oscillent entre les mondes. Au premier je dirais que sans code cela nest pas vrai, ce nest quun transfert de code, de C# vers Xaml, dun langage fortement typ et contrl vers un langage moins fiable de ce point de vue. Au second je dirais que Xaml est quand mme un peu plus quun langage pour dessiner des petits mickeys. Quant aux troisimes, sils shsitent cest quils soupsent les dangers de chacune de ces approches radicales. La vrit tant souvent ailleurs, et surtout au milieu, trouver la juste balance entre ces deux extrmes est vraisemblablement le meilleur choix StringFormat Puisque nous en sommes aux dtours et au formatage des valeurs dun binding, profitons-en pour aborder StringFormat, un autre paramtre du binding. Ajout il y a peu au Framework standard et seulement partir de la version 4 sous Silverlight ce paramtre permet de contrler le formatage de la zone affiche et vite dans certains cas lobligation de crer un convertisseur de valeurs.
StringFormat reprend les options de la mthode String.Format (voir dans les rfrences en

dbut darticle String Format Options pour un billet regroupant les diffrents formats). Par exemple, reprenons laffichage de la ressource DateTime de lun des exemples plus haut. Par dfaut nous avons un affichage de type date + heure classique. Comment faire si nous ne voulons afficher quune date courte, sans heure, compose du nom du jour, du mois et de lanne sur deux chiffres ? Pour rsoudre ce problme il faudrait crire un convertisseur de valeur prenant un DateTime et acceptant un paramtre de format nous permettant dobtenir le rsultat (ce que vous venons de voir juste plus haut). On peut aussi crire un convertisseur spcifique retournant une chane formate comme nous le dsirons. En fait le choix est soit dcrire un convertisseur assez gnrique utilisant un paramtre (ce qui compliquera encore plus la syntaxe dans la balise de binding) soit dcrire un convertisseur de valeur spcifique (au risque, en bout de projet, davoir crit des dizaines de convertisseurs spcialiss, ce quon voit assez souvent en WPF il faut le dire). Le mieux est de profiter de StringFormat :

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

41

<TextBlock Text="{Binding Now, StringFormat='dddd-MM-yy'}" />

On voit lutilisation dun TextBlock et non dun Label car ce dernier a une proprit Content qui accepte un peu tout, et le StringFormat na aucun effet (si on passait une image comme Content on se demande en effet comment le formatage sy prendrait). TextBlock possde une proprit Text et le formatage sapplique donc correctement. Mais.. mais.. regardons la fiche un instant

Figure 10 - StringFormat en US

Et oui.. il y a un bug ! Le StringFormat se moque totalement de la culture et fonctionne en US. Damned ! Il y a une astuce pour corriger les choses, il suffit de surcharger la mthode OnStartup de App.xaml avec un bout de code magique (magique car si vous le devinez tout seul cest que, sans mentir, si votre ramage se rapporte votre plumage, vous tes le phnix des htes de ces bois !) :
protected override void OnStartup(StartupEventArgs e) { FrameworkElement.LanguageProperty.OverrideMetadata( typeof(FrameworkElement), new FrameworkPropertyMetadata( XmlLanguage.GetLanguage( CultureInfo.CurrentCulture.IetfLanguageTag))); base.OnStartup(e); }

Au design vous verrez toujours la date en anglais, mais { lexcution vous aurez le plaisir de lire la date dans la bonne culture. Lastuce corrige tous les aspects du formatage, comme par exemple lutilisation de la virgule au lieu du point pour les dcimaux en franais. Injection de culture On peut aller encore plus loin avec StringFormat, et pour reprendre une faon de parler trs la mode, faire de linjection de culture terme technique totalement invent pour loccasion je vous rassure, mais aprs tout, tout le monde jargonne sans trop savoir qui le premier invent le terme, ici au moins vous saurez que cest moi ! Il peut arriver quau sein dune application dont la culture est dj{ prise en compte (notamment par lastuce prcdente) on rencontre le besoin de formater une valeur selon une culture spcifique. Une application de traduction pourra ainsi vouloir prsenter un texte ou des donnes dans plusieurs langues { la fois. Limagination ne vous manquant pas, je vais me concentrer sur le comment : Supposons des TextBlocks dfinis dans un StackPanel. Le contexte de ce dernier sera le suivant :
Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

42

<StackPanel.DataContext> <sys:Int32>123</sys:Int32> </StackPanel.DataContext>

On retrouve lastuce consistant { crer une valeur constante comme DataContext, ici un entier de valeur 123. Le premier TextBlock sera dfini pour afficher le nombre en culture US :
<TextBlock Text="{Binding ConverterCulture='en-US', StringFormat='{}{0:N2}' }" />

Ce qui affichera 123.00, avec un point pour la sparation dcimale puisque nous avons indiqu un formatage avec 2 dcimales et un format US. Le second TextBlock sera identique la dfinition de la culture prs, en FR :
<TextBlock Text="{Binding ConverterCulture='fr-FR', StringFormat='{}{0:N2}' }" />

Ce qui affichera 123,00 puisque notre belle langue prfre la virgule au point en cet endroit. Certains curieux auront not les tranges accolades vides dans la chane de format Oui cest curieux, trange et mme bizarre. Encore une source de confusion et derreurs difficilement cernables dans un gros logiciel. Ninsistez pas je ne vous en donnerai pas lexplication ! Niet ! Bon cest bien parce que jai bon cur En fait, les chanes de format utilises sont celles de String.Format, et elles utilisent dj pour certaines des accolades amricaines (curly braces). Si on les utilisait directement il y aurait conflit avec les mmes symboles qui ont un sens particulier dans le binding Xaml. Le premier jeu daccolades vide permet en quelque sorte dannuler la signification des symboles, une sorte de squence escape permettant dutiliser derrire la chane de format qui comporte des accolades de mme nature. Voil, vous savez. Et mon article explose un peu plus en taille. Vous en assumez la responsabilit, cest bien et je vous en remercie Le ContentStringFormat Oui, il y a encore une option de formatage Utile comme les autres bien sr, mais cest un peu comme trop de crme chantilly sur un gros gteau, au dbut cest apptissant, mais si on en met vraiment de trop a devient curant Attention { loverdose, dbut de la perte de maitrise, fille de tous les vices et surtout du code spaghetti ! Cette option de formatage ne fonctionne que sur les contrles offrant un Content, donc ContentControl, ContentPresenter, le Label et le TabControl (jen oublie peut-tre). Elle a lavantage de remplir un vide et de sappliquer hors du binding. Comme nous avons vu que le StringFormat fonctionne uniquement sur des proprits de type texte, il fallait bien une astuce pour les conteneurs. Prenons un bouton qui va dclarer un contenu numrique que nous souhaitons voir formater comme un montaire :

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

43

<Grid Name="GridContentFormat" > <Button ContentStringFormat="{}{0:C}" > <System:Int32>546</System:Int32> </Button> </Grid>

Ici la valeur afficher est un entier valant 546. Au design vous verrez la chose suivante :

Figure 11 - ContentStringFormat

Les dollars ne sont pas encore utiliss en Europe, mais cest toujours le mme bug qui sillustre. Grce la solution prsente plus haut et intgre App.xaml, { lexcution nous retrouverons bien heureusement notre chre (trs chre) monnaie :

Figure 12 - ContentStringFormat corrig

Grer les nuls Il ne sagit pas ici de trouver une occupation { ceux qui nauraient pas russi suivre cet article, non, juste de se demander ce quil se passe dans le cas dun binding avec formatage sur une source qui peut retourner une valeur nulle Si, je vous lassure, il se passe quelque chose. a plante. Pour faire court voici la syntaxe de loption TargetNullValue qui sajoute bien videmment { tout ce que la chane de caractres dfinissant le binding contient dj (!) :
<TextBox Grid.Column="1" Grid.Row="1" Margin="0,11,11,11" VerticalAlignment="Top" Text="{Binding Path=NumberOfComputers, TargetNullValue={x:Static sys:String.Empty}, StringFormat=\{0:D\}}" />

Dans cet exemple le TargetNullValue est sous bind une ressource statique qui est String.Empty. Dans le cas o la source de binding est nulle, cest donc cette valeur qui sera

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

44

reprise et non le formatage par StringFormat. On pourrait bien entendu dfinir toute autre valeur, voire une constante chane. Autant dire quil sagit l{ dune simplification qui complexifie aussi les balises de binding et qui renforce bien entendu les craintes que jexprime en introduction et qui explique aussi pourquoi personne ne connait rellement toutes les options du binding Mais cela peut rendre service si la stratgie dutilisation est clairement dfinie et documente.

Le Binding Multiple
Encore une option rcente qui, si elle renforce le potentiel du binding, rajoute sa petite dose de complexit. Une dose par ci, une dose par l{, ldifice devient difficilement matrisable et les drapages du code spaghetti ne se cachent pas loin, alors restez vigilant ! Le MultiBinding est une rponse une problmatique simple : imaginons que vous deviez afficher un texte format constitu de plusieurs valeurs diffrentes et que vous souhaitiez, bien naturellement, que laffichage se mette { jour si lun ou lautre des fragments change. Une autre problmatique laquelle le MultiBinding rpond aussi, et cest peut-tre l son intrt le plus grand, cest la capacit { agrger plusieurs valeurs pour en crer une seule { la sortie. Imaginez simplement trois sliders permettant de rgler le niveau du rouge, du vert et du bleu dun rectangle, donc de la couleur de sa proprit Fill. Arriver mixer les trois valeurs indpendantes pour crer une couleur ou directement une brosse qui pourra tre lie par binding la proprit Fill du rectangle peut, si cela est bien utilis, aller vers une simplification du code (puisque quon supprime tous les gestionnaires dvnements de changement de valeur des sliders). Toutefois le MultiBinding ne vous vitera pas un passage par C# car il faut un convertisseur spcial pour grer la situation (ce qui se comprend assez facilement). Vous trouverez dans les rfrences en dbut darticle ladresse dun tutor portant sur le MultiBinding, je vous conseille dy faire un tour pour complter mes explications. Ici je vais me contenter de lier la proprit Text dun TextBlock aux proprits Nom et Prenom dune instance de la classe Personne cre pour loccasion et de formater le tout comme suit : Prenom, Nom. La classe Personne Je vous la prsente brivement car je men resservirai plus loin :

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

45

public class Personne : INotifyPropertyChanged { private string nom = string.Empty; public string Nom { get { return nom; } set { nom = value; doChanged("Nom"); } } private string prenom = string.Empty; public string Prenom { get { return prenom; } set { prenom = value; doChanged("Prenom"); } } public event PropertyChangedEventHandler PropertyChanged; private void doChanged(string propertyName) { var p = PropertyChanged; if (p == null) return; p(this, new PropertyChangedEventArgs(propertyName)); } }

Rien

particulier, une classe avec deux proprits et supportant INotifyPropertyChanged. Vous noterez la faon dont doChanged est programm en crant une variable locale depuis PropertyChanged. Cette stratgie est conseille pour viter certains problmes en multithreading. Une bonne habitude prendre mais que, hlas, je ne dvelopperai pas dans cet article (dj bien charg malgr tout). Le code du multi convertisseur Comme cet exemple se veut court et que larticle porte sur Xaml et le binding plus que sur C#, jai conu un convertisseur multiple assez minimaliste, le voici :

de

bien

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

46

class PersonneMultiConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { var nom = (string) values[0]; var prenom = (string) values[1]; return prenom + ", " + nom; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { return new object[] {}; } }

Les multi convertisseurs se diffrencient des convertisseurs simples par linterface quils supportent : IMultiValueConverter. Le principe reste le mme, une mthode Convert et une autre ConvertBack pour convertir les donnes dans lautre sens. Le code ci-dessus nimplmente quun seul sens et formate les donnes comme annonc plus haut. Le code Xaml La ressource est cre de la faon suivante :
<Window.Resources> <local:Personne x:Key="Personne" Nom="Dahan" Prenom="Olivier" /> </Window.Resources>

Le TextBlock est programm comme suit (les balises ont t fortement clates pour rendre la dcomposition plus vidente) :
<Grid Name="GridMultiBinding" DataContext="{StaticResource Personne}"> <TextBlock> <TextBlock.Text> <MultiBinding Converter="{StaticResource PersonneMultiConverter}" > <MultiBinding.Bindings> <Binding Path="Nom"/> <Binding Path="Prenom"/> </MultiBinding.Bindings> </MultiBinding> </TextBlock.Text> </TextBlock> </Grid>

On peut illustrer le MultiBiding de faon malgr tout plus simple en vitant le convertisseur. Toujours au sein de la mme grille dfinissant le DataContext sur linstance de la classe Personne dfinie en ressource, nous pouvons crire :

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

47

<TextBlock> <TextBlock.Text> <MultiBinding StringFormat="Nom: {1} {0}"> <Binding Path="Prenom" /> <Binding Path="Nom" /> </MultiBinding> </TextBlock.Text> </TextBlock>

Ici nous navons pas besoin de convertisseur, cest bien plus pratique (mais moins riche en possibilits). Lordre des champs traits est indiqu juste au dessus de leur apparition l{ o le convertisseur prcdent tait oblig dassumer un ordre fixe (source de bug). Les possibilits ne sont pas exactement les mmes mais cette forme de MultiBinding est peut-tre la plus intressante pour une utilisation au quotidien dans le sens o elle simplifie le code sans ajouter trop dlments { contrler manuellement (comme lordre des paramtres dans le convertisseur).

Le Binding XML
Le binding XML est peut-tre celui qui est le plus bluffant. Les sources XML ne sont jamais trs simples traiter. Le Binding Xaml montre ici toute sa puissance en offrant une syntaxe claire et concise. Mais cest une syntaxe de binding de plus { connatre et { matriser ! Binding sur une source Web
Syntaxe : DataContext="{StaticResource DotBlog}" ItemsSource="{Binding XPath=item/title}"

Rpertoire : Sample3 Projet : xmlBinding

Dans cet exemple syntaxique un DataContext est li une source XML dclare par le biais dune ressource XmlDataProvider. Le chemin { afficher est donn par lexpression XPath, ici item/title . Prenons lexemple de bout en bout pour mieux comprendre. Le Framework offre la classe XmlDataProvider qui se charge de crer un lien avec une source au format XML. Dautres moyens daccder { une source XML existent, Linq To XML par exemple. Cela scartant de notre sujet regardons juste comment la source est dfinie ct Xaml (projet exemple XmlBinding) :
<Window.Resources> <XmlDataProvider x:Key="DotBlog" XPath="rss/channel" Source="http://www.e-naxos.com/blog/syndication.axd" /> </Window.Resources>

Le plus simple pour trouver une source XML est daller la chercher sur le Web Ici le XmlDataProvider pointe tout simplement le flux RSS de mon blog (et le chemin rss/channel { lintrieur de la source). On peut ds lors crer un binding avec une Listbox pour rcuprer tous les titres du blog :

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

48

<ListBox DataContext="{StaticResource DotBlog}" ItemsSource="{Binding XPath=item/title}" />

Et cest tout. Dj{ au design la ListBox se remplit des donnes. Excutons et voyons le rsultat :

Figure 13 - Binding XML

Il y a quelque chose dun peu magique dans ces deux ou trois lignes de Xaml qui crent une application capable de lister un flux RSS sans aucun code behind. Imaginons juste quelques instants la quantit de code et de librairies externes que cela aurait ncessit dans les environnements davant Xaml, davant .NET. Cest le cot clair de la force du binding. Ne jamais sous-estimer pour autant la puissance du ct obscur ! Binding sur une source XML en ressource Les possibilits du binding sont telles quil existe plusieurs faons dobtenir le mme rsultat. Le mieux est de voir un autre exemple dutilisation de source XML. Ici nous crons un rpertoire data dans le projet et nous y ajoutons un fichier XML. Cette source contient une liste de livres. Le fichier XML est plac en ressource de lapplication. La dfinition de la source est trs proche de celle de lexemple prcdent :
<XmlDataProvider x:Key="Books" Source="data/8534-4594.xml" XPath="Books/Titles" />

La cl dfinit le nom de la ressource, la Source pointe le fichier XML, et le XPath indique le chemin qui nous intresse (la balise Books englobe tout le fichier, chaque livre est une entre Titles). Ce qui nous intresse cest le binding, alors regardons maintenant comment une Listbox est lie cette source :

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

49

<ListBox ItemsSource="{Binding Source={StaticResource Books}}" DisplayMemberPath="title" />

Vous noterez que cette fois-ci je nai pas utilis le DataContext. Puisque seule la liste est lie la source on peut dfinir le binding directement sans passer par cet intermdiaire. De fait la source du binding est lie la ressource statique Books cre plus haut. En fixant le DisplayMemberPath on choisit ici de nafficher que le contenu de la balise title de chaque livre.

Figure 14 - Binding XML depuis un fichier en ressource

Binding sur une requte Linq To XML Il nest videmment pas question de traiter de toutes les manires daccder { une source XML et encore moins dentrer dans les dtails de Linq To XML. Mais voici un cas pratique quon pourrait croire simplement driv des exemples prcdents qui sont fort simples, ce qui nest pas le cas. Les difficults rencontres ne concernent pas le binding lui-mme mais laccs au fichier XML en ressource et son traitement en Linq To XML. Le binding repose ensuite sur un ObjectDataProvider plutt quun XmlDataProvider auquel il faut accder par code pour en initialiser la source. Plus quelques autres dtails. Do lintrt de cet exemple : la multiplicit des petites difficults. La source XML sera la mme que celle des exemples prcdents, un fichier plac en ressource de lapplication (projet exemple xmlBinding). La partie Xaml est simple, on commence par crer une ressource ObjectProvider :
<Window.Resources> <ObjectDataProvider x:Key="Linq" /> </Window.Resources>

Il ny a pas de source dclare ici car nous allons traiter le fichier XML avant de le transformer en source utilisable. Dans la liste des livres nous souhaitons extraire tous les livres ayant un prix infrieur 20 euros et les classer par ordre dcroissant de prix. Cela nempche en rien de dfinir la ListBox et son binding :

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

50

<ListBox ItemsSource="{Binding Source={StaticResource Linq}}" DisplayMemberPath="FullDescription" />

Nous avons prvu de retourner un type anonyme dont lune des proprits sappellera FullDescription (une concatnation du prix et du titre). Ct binding les jeux sont faits. Reste coder la logique. Sans trop entrer dans les dtails voici le code qui ralise tout cela :
StreamResourceInfo sr = Application.GetResourceStream( new Uri("xmlBinding;component/data/8534-4594.XML", UriKind.Relative)); var xr = new StreamReader(sr.Stream); XDocument xd = XDocument.Load(xr); var nfi = new NumberFormatInfo(); nfi.NumberDecimalSeparator = "."; var q = from x in xd.Descendants("Titles") where x.Element("price") != null let price = double.Parse(x.Element("price").Value, nfi) where price < 20d orderby price descending select new { Title = x.Element("title").Value, Price = price, FullDescription = price.ToString("##0.00") + " " + x.Element("title").Value }; var p = Resources["Linq"] as ObjectDataProvider; if (p!=null) p.ObjectInstance = q;

En partant du dbut (cest plus simple !), le code ci-dessus ralise les choses suivantes : Obtention dun objet StreamResourceInfo sur le fichier XML plac en ressource de lapplication. Dclaration dun StreamReader sur le flux de lobjet prcdent pour le lire. Cration dun XDocument par chargement du flux. Comme les prix sont stocks au format amricain (avec un point pour les dcimales) le code cr un NumberFormatInfo qui est modifi pour indiquer cette particularit. Vient ensuite la requte Linq To XML qui slectionne tous les livres cotant moins de 20 euros et qui les classe par ordre dcroissant de prix. La requte retourne un type anonyme contenant le prix, le titre, et le FullDescription qui nest que la concatnation des deux autres champs. Reste { rcuprer linstance de lObjectDataProvider qui a t dfini en Xaml dans les ressources de la fentre, puis assigner le rsultat de la requte sa proprit Source.

Excutons :

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

51

Figure 15 - Binding sur le rsultat d'une requte Linq To Xml

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

52

Le Binding Relatif
Tout est relatif dans la vie mme le Binding ! En effet, nous avons vu jusquici diffrentes formes de binding mais toutes avaient en commun de rfrencer explicitement une source fixe : DataContext, proprit, expression XPath. Or, il se trouve des cas o le binding doit pouvoir tre exprim de faon plus nuance. Cest le binding dit relatif, avec sa syntaxe bien lui, comme on peut sy attendre. Il existe plusieurs formes de binding relatif : Self TemplatedParent FindAncestor PreviousData Binding to Self Dans un tel titre autant crire tout en anglais. (amusant non ?) Pour rester dans lamusant (enfin, pas hilarant non plus, nexagrons rien), voici un exemple dont je vous demande dimaginer le rsultat avant de lire lexplication :

Rpertoire : Sample4 Projet : RelativeBinding

<TextBlock Text="{Binding RelativeSource={RelativeSource Self}, Path=Background}" Background="Chartreuse" />

a donne quoi votre avis ?

Figure 16 - Binding to Self

Oui, le TextBlock se regarde le nombril. En liant sa proprit Text une source relative bien spciale (Self) et la proprit Background de celle-ci, on force le TextBlock crire le code de sa propre couleur ! Ce qui est plus intressant est bien entendu la syntaxe de cet amusant regard sur soi-mme de lobjet. Car si les objets nont pas dme, ils pratiquent grce au binding relatif le Connais-toi toi-mme de Socrate

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

53

Le TemplatedParent Binding Lintrt de ce binding particulier est peut-tre plus grand encore que le prcdent, il sagit ici de pouvoir effectuer un binding sur une proprit du template de contrle dans lequel lobjet crant le binding se trouve. Prenons rapidement un exemple pour viter le flou. Imaginons un bouton qui possde un template. A lintrieur de celui-ci crons divers lments imbriqus dont un TextBlock qui, de faon similaire { lexemple prcdent, va se lier par binding la proprit Name du TemplatedParent, soit du parent du template, donc le bouton. Le code Xaml est le suivant :
<Button Name="LeBoutonParent" Content="LeBouton"> <Button.Template> <ControlTemplate x:Name="TemplateDuBouton"> <StackPanel Name="StackPanelInterne"> <TextBlock Background="Aquamarine" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Name}"/> </StackPanel> </ControlTemplate> </Button.Template> </Button>

Le rsultat visuel est alors le suivant :

Figure 17 TemplatedParent Binding

Visuellement notre bouton est mconnaissable et nest pas vraiment look cest le moins quon puisse dire, mais ce nest pas ce qui nous intresse ici. Nous voyons un espace occup par une couleur de fond et un texte indiquant LeBoutonParent . La couleur provient du Background du TextBlock lui-mme (Aquamarine), quant au texte quil affiche il provient de la proprit Name de lobjet en cours de templating, c'est--dire le bouton. Ce type de binding { lintrieur dun template permettant de rfrencer lobjet parent du template est trs puissant puisquil saffranchit de rfrences explicites. Si le template tait dfini dans un dictionnaire de ressource au lieu dtre intgr au bouton, il serait facilement applicable { dautres boutons, et tous afficheraient ainsi leur nom alors que tous seraient des instances diffrentes possdant un nom diffrent. La technique peut tre utilise des choses plus utiles, cela va sans dire et elle fait partie des astuces utilises dans lart du templating (qui seffectue le plus souvent sous Expression Blend).

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

54

Le Binding sur recherche danctre Voici une autre forme de binding relatif. Son intrt : permettre de se lier non plus soimme, pas mme { lobjet parent du template, mais { nimporte quel objet de larbre visuel dot dun type bien particulier quon spcifie. Il est difficile de donner des exemples concrets de lutilisation de ces formes si particulires de binding sans avoir prsenter des objets complexes au sein de projets qui le sont tout autant. Cest pourquoi mes exemples de templating sont ici courts, mais moches, avouons-le ! Votre imagination est un champ infini, le binding sur recherche danctre est une des cls qui permet den ouvrir les portes Reprenons toutefois lexemple prcdent et ajoutons deux autres TextBlock { lintrieur du StackPanel du template du bouton (je ne vous donne que la dclaration de ces deux contrles, regardez le code du template un peu plus haut. Noubliez pas non plus le projet RelativeBinding dans lequel se trouve les sources de cet exemple) :
<TextBlock Background="Azure" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}, Path=ToolTip}"/> <TextBlock Background="CadetBlue" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type StackPanel}}, Path=Name}"/>

Le rsultat visuel est :

Figure 18 - Binding sur recherche d'anctre

Le premier TextBlock cr un binding sur une source qui est dfinie comme tant une recherche sur tous les anctres visuels du contrle courant, recherche devant sarrter ds quelle trouve un lment de classe Button. Quand cela est fait, le binding est cr sur la proprit ToolTip de ce dernier. Noubliez pas que tout cela se tient { lintrieur dun bouton templat mme si visuellement on ne voit plus rien qui ressemble un bouton. Et cest bien le texte du ToolTip du bouton que nous voyons en seconde ligne (la premire ligne provenant de lexemple prcdent). Mais on peut aller plus loin avec la recherche danctre, par exemple en indiquant le niveau de profondeur recherch. Ainsi, le second TextBlock de cet exemple (le troisime au total) indique-t-il, en plus du type danctre recherch (le type StackPanel), un niveau de recherche o sarrter : la valeur 1. De ce fait cest le StackPanel interne, celui qui est dfini { lintrieur du template, qui est trouv. Une fois la localisation de ce contrle effectue, le binding est cr sur la proprit Name de ce

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

55

dernier. Cest pourquoi la troisime ligne affiche indique StackPanelInterne , valeur de la proprit Name du StackPanel contenu dans le bouton (voir le code du template plus haut). Peut-on aller encore plus loin ? Oui, car le binding sur recherche danctre (visuel), tel un passe-muraille est capable de sortir des frontires du template en cours, mme de dpasser les limites de lobjet dfinissant le template ! Imaginons que nous ajoutions un autre StackPanel qui ne fait quentourer le bouton de lexemple. En toute logique appelons-le StackPanelExterne. Il sagit donc dun parent visuel du bouton sans aucun lien avec ce dernier que cette parent visuelle, cela pourrait tre un Canvas, une Grid ou tout autre conteneur. Il est alors possible de rfrencer ce contrle par un binding sur recherche danctre en indiquant un niveau de profondeur de 2 (le niveau 1 tant rencontr lorsque la recherche trouve le StackPanel interne) :
<TextBlock Background="Coral" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorLevel=2, AncestorType={x:Type StackPanel}}, Path=Name}"/>

Figure 19 - Binding sur recherche d'anctre avec niveau de profondeur

La dernire ligne ajoute indique bien le nom du StackPanel externe, cest { dire celui qui est au-dessus du bouton dans larbre visuel. Cette technique est assez risque malgr tout. Tant quon reste { lintrieur du template ou de lobjet qui le supporte on sait { lavance ce qui peut sy trouver. Ds lors quon tente de rfrencer des objets extrieurs on prend le risque quune modification du visuel fasse scrouler le binding et le fonctionnement de linterface visuelle. Imaginons simplement dans notre exemple que nous dcidions de changer le StackPanel extrieur en une Grid, le dernier binding tudi ne fonctionnera plus. Le risque de rgression est donc trs grand. Nous avons vu le binding rflexif et socratique, le binding gendarme, sachant toujours se rfrer { sa hirarchie, et enfin le binding spectre traversant les murs Un drle de bestiaire mais qui, bien exploit, confre une puissance incroyable { Xaml. Hlas, je noublie pas lun des thmes de cet article : vous avertir des dangers du binding. Toutes ces formes alambiques de ligatures, et encore plus ces dernires codant des niveaux de recherche dans des types se trouvant dans larbre visuel, toutes ces techniques puissantes sont malheureusement trs dlicates appliquer sans se prendre les pieds dans le tapis, surtout sur de gros projets crits plusieurs. Xaml est au final un langage comme les autres, mais il ne

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

56

dispose pas des analyseurs de code et du typage fort dun C#, ni mme dun dbogueur de qualit approchante. Toute erreur, tout bricolage, et pire encore tout code spaghetti cre par manque de matrise de la complexit de lensemble aboutira un difice incontrlable et presque impossible maintenir. Servez-vous de tout cela avec beaucoup de discernement et de doigt. Je ne vous encourage pas viter la nouveaut dans un rflexe conservateur et passiste, bien au contraire, sinon je masquerai toutes ces possibilits de Xaml au lieu de vous les dmontrer. Non, mon message est clair : soyez hyper pro jusquau bout des ongles, et utilisez tout Xaml. Mais si jamais vous avez un doute sur votre matrise du sujet, ne sabotez pas votre projet : vitez ces complications, crivez du code C# qui sera facile maintenir. Vous ne passerez peut-tre pas pour un hros la machine caf, mais vous aurez le droit au sommeil du juste, celui qui a fait son travail proprement sans saboter le travail des autres. Cest peu, mais cest norme ! Le Binding PreviousData Parmi toutes les formes de binding cest peut-tre lune des moins connues. De toute faon depuis que nous avons quitt les premiers exemples de OneWay et TwoWay nous avons laiss depuis longtemps derrire nous la plage bonde de touristes et nous nageons en eaux profondes o seuls quelques gros poissons se risquent frayer. Certains ont de grandes dents, et cest pour cela que jattire { chaque fois votre attention sur la grande vigilance qui doit accompagner lutilisation de ces formes avances de binding Le mode RelativeSource PreviousData est malgr tout un mode de binding trs intressant. Nous avons vu jusqu{ maintenant des modes relatifs qui permettent de jouer avec larbre visuel : accs soi-mme (Self), ou aux autres contrles du template, voire ceux se trouvant encore plus haut dans larbre (FindAncestor). Quen est-il lorsque nous templatons des objets capables de prsenter des donnes (au sens large), c'est--dire des suites dobjets, et que dans le template que nous crons la prsentation ou la mise en page (ou tout autre lment du layout) dpend des donnes prcdentes ? Soyons encore plus clair. Imaginez un Bar Chart. Le Chart en lui-mme est conu pour afficher une srie de donnes. Chaque donne est affiche par un objet qui peut tre templat. Quand on crit le template des barres on ne lcrit quune fois. Bien entendu il sera appliqu { lidentique { chaque barre. Et au moment de la conception du template nous ne connaissons rien des donnes qui seront affiches, dautant quelles seront diffrentes chaque fois. Imaginons alors quau dessus de chaque barre nous souhaitions afficher un indicateur de tendance. Une petite flche oriente vers le haut ou le vers le bas selon que la donne en cours possde une valeur plus grande ou plus petite que la prcdente ? Ici aussi nous pourrions grer la chose ponctuellement en jouant avec les vnements du Chart et en crivant du code behind (quel que soit le contrle utilis pour crer le Chart). Mais il est vrai que ce nest pas dune grande lgance et que cette solution ne sera gure

Rpertoire : Sample5 Projet : PreviousDataBinding

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

57

portable dun Chart { lautre, sauf { recopier le code ou { le complexifier encore plus pour le rendre gnrique. Certains iront mme crer un UserControl spcifique pour rgler ce problme dencapsulation de code, complexifiant encore et encore la totalit du projet. Lcriture dun template applicable par un simple clic { tout objet Chart est de loin la solution la plus propre et la plus satisfaisante intellectuellement et techniquement. Mais il va falloir se dbrouiller pour que le template des barres soit capable de rfrencer la donne prcdente , celle de la barre affiche juste avant afin de grer le diffrentiel et afficher la bonne flche de tendance. Ci-dessous une capture du visuel de la dmo vous fera mieux comprendre le rsultat escompt. En haut de chaque barre du Chart on trouve le diffrentiel de progression ou de rgression relatif la barre prcdente ainsi quune flche verte ou rouge oriente vers le haut ou le bas. Cest pour obtenir cet effet que le mode de binding PreviousData va tre utile.

Figure 20 - Binding PreviousData

Le but de cet article tant toujours et encore le binding lui-mme et non le code annexe des projets de dmo, jai tent jusqu{ maintenant de vous prsenter des projets trs simples ne montrant que lessentiel. Ici, mme en faisant au plus juste, le code sera un peu plus toff puisque nous avons besoin de donnes, de template et de quelques convertisseurs pour faire marcher lensemble.

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

58

Premirement nous nallons pas utiliser de composant Chart plus ou moins sophistiqu, cela dmontrera en plus que les composants de base de WPF et Silverlight sont bien assez riches pour qui a un peu dimagination. Car en regardant la figure ci-dessus, pouvez-vous imaginer que le composant principal nest rien dautre quune simple Listbox ? Passons rapidement sur ce code annexe mais ncessaire au fonctionnement de la dmo : La source de donnes Le plus simple est de crer une classe drivant de ObservableCollection gnrant automatiquement une collection de 10 entiers alatoires :
class RecordsCollection : ObservableCollection<int> { public RecordsCollection() { var r = new Random(); for (var i = 0; i < 10; i++) Add(r.Next(200, 450)); } }

Il faut dclarer une instance de cette classe dans les ressources de la fentre en cours, avec en prambule lajout de lespace de nom dans la balise de la fentre :
xmlns:Data="clr-namespace:PreviousDataBinding.Data"

La ressource sera dfinie comme suit :


<Window.Resources> <Data:RecordsCollection x:Key="data"/> </Window.Resources>

La visibilit des flches : la magie de PreviousData et du Binding Multiple Les deux flches (verte et rouge) sont des Path. Pour la simplicit les deux flches sont affiches lune sur lautre, il faut donc, selon le cas, en cacher une et montrer lautre pour ne voir que celle qui correspond la tendance. Le projet PreviousDataBinding fourni avec larticle contient bien entendu la totalit du code. Pour linspection des ressources, des templates et des Path je vous conseille vivement dutiliser Expression Blend qui est mille fois mieux adapt pour ce genre de travail. Pour calculer la visibilit dune flche il nous faut connatre la valeur courante ainsi que la valeur de la prcdente barre du Chart. Comme indiqu plus haut le composant que nous templatons ici nest autre quune ListBox dont lItemPanelTemplate a t modifi pour utiliser un StackPanel en mode horizontal. Le template qui nous intresse est celui des items (ItemTemplate), cest lui qui dfinit les barres et les donnes affiches (textes et flches). Cest un DataTemplate que nous utilisons (voir le code source complet du projet). Pour obtenir la valeur courante et la prcdente en mme temps il faut dfinir un Binding Multiple que nous avons dj tudi.

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

59

Voici un extrait du DataTemplate, au niveau de la dfinition du Path reprsentant la flche verte (rappelons que par dfaut la rouge est Collapsed et que nous ne nous occupons que de rendre la verte visible ou invisible) :
<Path.Visibility> <MultiBinding Converter="{StaticResource RecordsToVisbilityConverter}"> <Binding/> <Binding RelativeSource="{RelativeSource PreviousData}"/> </MultiBinding> </Path.Visibility>

Plusieurs choses sont { noter ici : la premire est lutilisation dun multiple binding que nous avons dj{ indiqu. On remarque lutilisation dun convertisseur. Ensuite vient le contenu mme de ce binding qui est form de deux valeurs, lune exprime comme un binding { litem courant de la collection et lautre utilisant le fameux PreviousData. Lexplication est finalement assez simple : En dfinissant un binding multiple nous faisons en sorte de pouvoir traiter plusieurs valeurs la fois. Ces valeurs sont au nombre de deux : la valeur courante de la barre et la valeur de la barre prcdente. Cest pour cela que nous avons deux bindings dans la balise multiple. Le premier est un binding simple (item courant de la collection) qui reprsente la valeur courante de lItem de la ListBox (puisque cest cet Item que nous templatons au travers dun DataTemplate). Rappelons que la source de donnes de la ListBox nest autre que lobjet collection que nous avons prsent un peu plus haut, objet qui retourne une liste de dix valeurs entires alatoires. Cest donc une telle valeur entire unique que devra traiter le DataTemplate. Dans dautres cas le DataTemplate peut avoir traiter un objet plus complexe quun entier (une fiche article, une facture). En choisissant un item aussi simple quune instance de int on ne peut pas simplifier plus lexemple Le second binding utilise enfin le mode RelativeSource PreviousData qui retourne la valeur prcdente, donc relative la position de la valeur courante. Donc lentier prcdent dans la collection source de la ListBox. Arms de ces deux bindings qui nous permettent dobtenir les deux valeurs qui nous intressent, utilisons la capacit du binding multiple pour fusionner ces dernires en une information diffrente : la visibilit du Path. Cest grce au convertisseur spcial du Multi Binding que nous pouvons raliser ce tour de force. Voici le code de ce dernier :

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

60

public class RecordsToVisibilityConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) { int currentValue, previousValue; var result = Visibility.Visible; if (values[0] == null || values[1] == null) return result; if (!int.TryParse(values[0].ToString(), out currentValue)) return result; if (!int.TryParse(values[1].ToString(), out previousValue)) return result; if (previousValue > currentValue) result = Visibility.Collapsed; return result; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } }

Lintrt dutiliser un multi binding se rvle donc ici : il permet dobtenir plusieurs valeurs et son convertisseur sait traiter toutes ces valeurs pour en fabriquer une nouvelle (valeur de sortie) qui peut tre de tout type. Ici, cest une valeur de visibilit que nous crons selon le diffrentiel entre les deux valeurs dentres reues. Vous aurez not que le multi binding (voir plus haut) est inscrit dans une balise Path.Visibility. Cest donc bien une valeur de visibilit que nous retournons et qui affectera directement la visibilit de la flche verte. Vous allez me dire, certes, mais la flche rouge alors ? On voit bien la forme des flches que si elles taient juste superposes on verrait les pointes de la flche se trouvant sous la premire Et dans la dfinition du code Xaml de la premire flche (non concerne par le binding que nous venons de voir) il ny aucun convertisseur connect ni aucun binding, comment peut-elle devenir visible lorsque la flche verte est cache (rsultat du calcul du binding) ? On pourrait tre tent dimplmenter le mme mcanisme de binding sur la premire flche, il suffirait de passer un paramtre supplmentaire au convertisseur pour lui indiquer de fonctionner dans un sens ou son inverse. Mais cela serait se compliquer la vie pour pas grand-chose (ainsi que le code qui entrerait alors dans le menu des spcialits italiennes, les fameux code spaghetti !). Il y a bien plus simple. Il suffit de dclarer maintenant un Property Trigger dans notre template en surveillant le changement de la valeur Visibility de la flche verte. Lorsque cette valeur change il ne reste plus qu{ appliquer son contraire { la flche rouge et le tour est jou ! En ralit cest mme plus simple puisque par dfaut la flche rouge est Collapsed. Il nest donc

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

61

ncessaire de pister que le changement de visibilit de la flche verte quand elle passe Collapsed. Puisque lorsquelle est visible la rouge est dj{ cache par dfaut Cest ainsi que dans le DataTemplate (celui que nous crivons en ce moment et qui sera utilis comme template dItem pour la ListBox) nous trouvons :
<DataTemplate.Triggers> <Trigger SourceName="GreenArrow" Property="Visibility" Value="Collapsed"> <Setter TargetName="RedArrow" Property="Visibility" Value="Visible"/> </Trigger> </DataTemplate.Triggers>

Quand la flche verte voit sa proprit Visibility passer Collapsed, alors nous changeons la visibilit de la flche rouge Visible. Voil quoi peut servir le mode PreviousData du binding relatif. Ce nest quun exemple, trs simple bien quutilisant plusieurs astuces. Jespre que mes explications sont assez claires et que cela est en train de faire bouillonner vos neurones qui se demandent maintenant comment utiliser cela dans un projet ! Le contenu des textes Le mcanisme est en gros le mme pour les textes. Il est mme plus simple puisque les deux textes sont toujours visibles, seul le contenu de lun est obtenu par calcul grce un multi binding faisant la diffrence entre la valeur en cours et la prcdente.

Rpertoire : Sample6 Projet : TemplateBinding

La technique de binding utilise tant identique, je renvoie le lecteur au code source o il trouvera tout ce quil faut pour dissquer lui-mme cette partie de la dmo (code Xaml, autre convertisseur RecordsDifferenceConverter, etc). Le Template binding Cette forme de binding relatif est particulirement utile. Il sagit de pouvoir rfrencer directement une proprit nomme dans llment sur lequel le template est appliqu. La syntaxe conventionnelle :
Laproprit = "{Binding RelativeSource={RelativeSource TemplatedParent}, Path=XXX}"

Le Path est celui de la proprit vise. La syntaxe raccourcie :


Laproprit = "{TemplateBinding xxxx}

Cest ce raccourci qui donne dailleurs son nom usuel { cette forme de binding, le template binding. Utilit Il est bon de dire quelques mots sur cette forme de binding car elle joue un rle trs important dans la cration des templates bien conus.

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

62

Prenons lexemple dun bouton. Crons un template pour changer son look & feel. Retirons tout ce que le bouton contient pour construire quelque chose dautre. Ici nous allons supposer quelque chose dextrmement simple qui du point de vue visuel sera assez laid, mais lesthtique nest pas lobjet de notre propos. Donc pour templater ce bouton, une fois que nous lavons vid de tout ce quil contient, ajoutons un rectangle que nous remplissons en vert, ajoutons un ContentPresenter, et voil. Un joli bouton rectangulaire, vert, affichant par dfaut le mot Button . Ce bouton ne gre aucun changement dtat visuel mais cela na pas dimportance pour la dmo. Vous limaginez bien ce template de button ? Ok (il faut dire que jai vraiment choisi quelque chose de simple !). Maintenant sur votre fiche, placez un bouton et appliquez-lui le template. Le bouton devient un rectangle vert avec le texte par dfaut affich. Super. Maintenant vous vous dites, ce vert est vraiment pouvantable dans mon application qui joue plutt sur les tons de bleu. Autant ce magnifique look flat rectangulaire me plait, autant, ce vert Qu{ cela ne tienne ! Votre bouton tant slectionn, vous regardez dans ses proprits et vous dcidez dattribuer un joli bleu issu de votre charte de couleurs { la proprit Background. Rien. Le bouton reste ostensiblement vert. Vous tentez une autre couleur (linformaticien ne savoue pas vaincu au premier essai). Rien. On dirait mme quil se moque de vous non ? Il est vert et restera vert. Vous, vous devenez rouge de colre avant dtre finalement vert de rage !

Figure 21 - Template Binding Cration du template sous Blend

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

63

Sous Expression Blend en mode templating voici quoi ressemble notre bouton (ci-dessus). Posons un second bouton sur la fiche :

Figure 22 - Template binding - application du template 1/2

Et appliquons-lui le template :

Figure 23 -Template binding - application du template 2/2

Tentons de changer sa couleur :

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

64

Figure 24 - Template binding - Essai de changement de Background

Il reste vert Cest agaant pour celui utilise le template. Cest frustrant de voir cette belle palette de couleur navoir aucun effet sur ce bouton alors mme quil existe une proprit Background et quon peut visiblement la changer. Mais cela ne sert rien, comme si quelque chose tait cass. Cest bien ce qui sest produit. En vidant le template original du bouton nous avons cass la mcanique visuelle ainsi que tous les liens qui existaient entre la classe Button et sa reprsentation visuelle De fait, la proprit Background de Button, si elle existe toujours (la classe Button na pas chang) ne sait plus { quoi sappliquer. Comment le bouton pourrait-il deviner que le Background doit maintenant tre appliqu au Fill dun Rectangle ? Et notre template est simplissime, dans un vrai template il y a souvent plusieurs objets (pour crer leffet glossy, pour grer ltat disabled, etc) comment le bouton pourrait-il deviner lequel joue le rle de Background visuel ? Cest impossible voil{ tout. La magie nexiste que dans les spectacles de music-hall. Il faut une intervention humaine pour expliquer au template quon dsire que la proprit Fill du Rectangle soit lie la proprit Background du contrle en cours de templating. Cest { cela que sert le mode TemplateBinding. Sous Expression Blend cela est trs simple mettre en place en quelques clics.

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

65

Figure 25 - Template binding - cration du lien sous Blend

Comme le montre la figure ci-dessus, Expression Blend permet de dfinir ce fameux lien entre une proprit de lun des objets du template avec une proprit compatible appartenant au modle (la classe sur laquelle sapplique le template).

Figure 26 - Le button correctement templat

Maintenant que le template a t correctement conu il est possible { lutilisateur de ce dernier de pouvoir changer la couleur du bouton en modifiant sa proprit Background. Le template sait maintenant comment relier cette proprit { leffet visuel recherch (ici changer la proprit Fill du Rectangle).

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

66

Expression Blend a cr pour nous le code Xaml, le voici :


<Rectangle Fill="{TemplateBinding Background}" Stroke="Black" />

Cest la version courte que Blend utilise pour crer ce binding et non la syntaxe plus longue de binding relatif. On comprend dailleurs la raison dtre dune syntaxe raccourcie, cest que ce binding bien particulier est trs utilis (ou devrait ltre, ce qui fait une nuance, hlas) ! Dans fourni Templatebinding vous trouverez deux templates, ButtonControlTemplate1, le template mal conu qui est accroch au premier bouton (celui qui reste vert) et ButtonControlTemplateCorrig, le template corrig qui permet de changer la couleur du bouton. Le template binding (ou liaison de modle) est ainsi un outil dont la comprhension est indispensable pour qui veut crer des templates utiles et versatiles. Dernire question : Lorsque japplique un template binding, par exemple au Background comme dans lexemple que nous venons de voir, je nai plus de contrle sur la couleur de fond de mon objet ! Si je veux quil soit vraiment vert, mme si aprs lutilisateur du template peut changer cette valeur, comment faire pour quil y ait une couleur par dfaut diffrente de celle du contrle original ? La question est lgitime La rponse tient en un mot : Style. Il suffit de crer un style qui fixe les paramtres comme le Background, style qui englobera le template. Expression Blend le fait automatiquement, tout template est cr avec un style lenglobant. Si on code sous VS ou directement en Xaml la main , il ne faut pas oublier ltape du style. Pour bien comprendre le rle de chacun (qui semble tre confus pour beaucoup de dveloppeurs), le template sert modifier la forme, le look & feel, le style sert fixer des valeurs aux paramtres de lobjet. Cest dans le template quon cre un bouton rond au lieu de rectangulaire, mais cest dans le style (et aprs application du template binding) quon fixe une couleur verte par dfaut au bouton. le projet

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

67

Le Collection Binding
Son but est assez simple : permettre un binding directement sur litem courant dune collection lorsque le DataContext est un objet de ce type. Prenons lexemple dune ListBox affichant une liste de personnes. La ListBox est place dans la grille principale de la fentre, cest cette dernire qui possde le DataContext. Ce dernier pointe une ressource qui est une ObservableCollection constitue ditems de type Personne (une classe ayant deux proprits : Nom et Prnom). La ListBox possde un ItemTemplate, dfini sous la forme dun DataTemplate plac dans les ressources de la fentre. Ce DataTemplate utilise pour sa part un binding que nous avons dj vu, le binding simple faisant implicitement rfrence au DataContext (syntaxe {Binding xxx}). Chaque item affiche ainsi le nom et le prnom de la personne. Maintenant, nous souhaitons poser sur la mme grille (donc partageant le mme DataContext que la ListBox) une zone prcisant la slection actuelle mais sans passer par la ListBox, uniquement en se rfrant { llment courant du DataContext, donc de la collection sous-jacente. Regardons le rsultat (projet exemple ListBinding) avant daller plus loin :

Rpertoire Sample7 Projet ListBinding

Figure 27 - Le Collection Binding

On voit que litem slectionn dans la ListBox est le second (trait bleu sur le ct gauche) et on peut voir que dans le cadre Votre slection se trouve exactement les mmes informations.

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

68

Les deux TextBlock de ce cadre sont programms comme suit :


<TextBlock Text="{Binding /Nom, Mode=Default}" /> <TextBlock Text="{Binding /Prnom, Mode=Default}" />

Pour la lisibilit jai supprim tout ce qui concerne la prsentation (couleur, position ). La syntaxe de ce binding particulier est ainsi {Binding /} pour se rfrer { llment courant de la collection, ou bien comme utilis ici {Bindind /xxx} o xxx est le nom de la proprit laquelle on souhaite se lier dans llment courant. Si le DataContext est un objet plus complexe qui contient une proprit de type collection, on peut encore utiliser cette syntaxe mais en prfixant le slash par le nom de la proprit collection. Par exemple avec un DataContext exposant une proprit Personnes (une collection), on crira {Binding Personnes/} pour litem courant, ou {Binding Personnes/Nom} pour se lier la proprit Nom de litem courant. Il faut noter que la notion ditem courant nest pas forcment automatique. Il faut que la position dans la collection soit gre par quelquun . Pour se faire on peut utiliser, par code, une CollectionView par exemple. Si, comme dans notre exemple, il y a une ListBox quon considre tre le pilote de litem courant, il faut alors positionner sa proprit IsSynchronizedWithCurrentItem true. Cest ce que fait notre exemple.

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

69

Le Priority Binding
Je croyais sincrement tre arriv au bout des types de binding et pouvoir aborder gentiment la fin de cet article qui, comme celui sur MVVM est devenu un livre lui-seul au fil des ajouts (record battu, MVVM ne faisait que 70 pages !) Hlas pour moi, mais heureusement pour vous, ma conscience me poussant toujours tout vrifier, je suis tomb sur un (je nose pas crire le mot) dernier ( ?) type de binding : le Priority Binding. Ce mode bien particulier propose de raliser une liste de bindings dans laquelle il existera une hirarchie, une priorit. Si le binding de plus haut rang retourne une valeur, cest elle qui deviendra la valeur courante, si ce binding choue cest le prochain sur la liste qui sera essay jusqu{ temps que lun des bindings de la liste retourne quelque chose. Lordre dans lequel les bindings sont parcourus pour obtenir une valeur est toujours le mme, cest celui fix par la liste, lordre des priorits. Cette vision est simplificatrice pour expliquer le fonctionnel, en ralit les choses sont plus subtiles nous allons le voir, notamment avec gestion de threads darrire-plan. Xaml ne passe pas son temps balayer la liste, bien entendu au final le binding actif est choisi dynamiquement mais en respectant les priorits fixes par la liste. Par exemple si un binding de faible priorit retourne une valeur en premier, elle deviendra la valeur active. Mais ds quun binding de rang plus lev retournera { son tour une valeur cest cette dernire qui deviendra la valeur active. On peut penser par exemple un binding de faible priorit allant puiser sa valeur dans une ressource locale (donc rapide) et un autre binding de rang plus lev mais allant chercher sa valeur dans le Cloud, donc plus lent mais peut-tre plus { jour. Tant que la valeur du Cloud nest pas arrive cest la valeur locale qui est affiche, ds que la valeur en provenance du rseau est disponible cest elle qui est affiche. Un autre exemple est celui de Word. Lorsque vous ouvrez un document, Word affiche le nombre de pages immdiatement, cest une estimation. Si le document est trs gros il faudra un peu de temps pour quil soit charg et analys, le nombre de pages affich deviendra alors le vrai nombre de pages du document. Si on devait raliser Word en WPF, on utiliserait le Priority Binding avec deux bindings : le premier pointerait sur une proprit estimation nombre de pages qui rsulterait dun calcul approximatif, de priorit basse, le second serait retourn par une proprit vrai nombre de pages de priorit haute retournant la valeur exacte. Aucune programmation, aucun timer ne serait ncessaire pour obtenir leffet recherch Pour rsumer, le Priority Binding savre trs utile dans des situations o des donnes assez lentes { obtenir ont un impact sur linterface visuelle. Pour viter que cette dernire soit dans un tat intermdiaire un peu en friche , on peut, grce au Priority Binding, proposer des valeurs dattente, rapidement calcules ou obtenues localement qui seront remplaces par les donnes dfinitives lorsquelles arriveront. Bref, vous avez compris lintrt je pense.

Rpertoire : Sample8 projet : PriorityBinding

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

70

Mettons tout cela en scne avec un exemple. Supposons une fentre affichant un TextBlock. La valeur affiche par ce dernier, un texte, sera puise de trois sources diffrentes mixes dans un seul Binding, un Priority Binding. La premire source sera trs rapide mais de faible priorit, la seconde un peu lente et de priorit intermdiaire, et la troisime trs lente mais de trs haute priorit. Pour simuler tout cela de faon simple, cest lobjet Window lui-mme qui fournira trois proprits. Une sera directe, les deux autres utiliseront un Thread.Sleep() pour ralentir leur lecture et simuler des sources lentes (gros calcul, accs Web). La gestion des threads sera automatiquement prise en compte par le Priority Binding pour peu quon indique un paramtre supplmentaire, notamment sur les proprits lentes utilisant un Thread.Sleep(). Cette option est IsAsync quon passe { true si on dsire que le binding ainsi marqu soit plac automatiquement en file dattente dans un thread darrire plan. La squence que le projet PrioriryBinding vous propose sera la suivante ds que vous lexcuterez : Immdiatement vous verrez cet affichage :

Figure 28 - Priority Binding - 1/3

Au bout dune seconde et demie laffichage va devenir le suivant :

Figure 29 - Priority Binding - 2/3

Au bout de trois secondes (en partant du premier affichage) laffichage va enfin devenir le suivant et ne changera plus :

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

71

Figure 30 - Priority Binding - 3/3

Fascinating ! (comme dirait M. Spock).

Voici les trois proprits dclares directement dans la fentre Window1 :

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

72

/// <summary> /// Ressource trs prioritaire mais trs lente obtenir... /// </summary> /// <value>The slow.</value> public string Slow { get { Console.WriteLine("Slow: " + Thread.CurrentThread.ManagedThreadId); Thread.Sleep(3000); return "Je suis lent, mais je suis prioritaire !"; } } /// <summary> /// Ressource assez lente obtenir de priorit intermdiaire /// </summary> /// <value>The medium.</value> public string Medium { get { Console.WriteLine("Medium: " + Thread.CurrentThread.ManagedThreadId); Thread.Sleep(1500); return "J'arrive ! je suis le Medium !"; } } /// <summary> /// Ressource trs rapide obtenir mais de priorit basse /// </summary> /// <value>The fast.</value> public string Fast { get { Console.WriteLine("Fast: " + Thread.CurrentThread.ManagedThreadId); return "Prem's, je suis hyper rapide !"; } }

Comme indiqu, la proprit rapide (Fast) ne possde aucun dlai, les deux autres un Thread.Sleep() de 1500 et 3000 ms. Vous noterez que chaque lecture de proprit est assortie dans le Getter dun affichage console retournant le numro du thread utilis, ce qui permet de confirmer que chaque accs bien lieu dans un thread spar gr automatiquement par le Prioriy Binding. Par exemple, pour lexcution retrace plus haut (voir les trois figures), on trouve dans la console de sortie :
Fast: 9 Medium: 11 Slow: 10

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

73

Laccs { Fast sest effectu via le thread 9, laccs { Medium via le thread 11 et laccs { Slow via le thread 10. Reste { voir comment tout cela est spcifi sous Xaml. Vous allez voir, cest trs simple :
<TextBlock> <TextBlock.Text> <PriorityBinding> <Binding ElementName="MainWindow" Path="Slow" IsAsync="True" /> <Binding ElementName="MainWindow" Path="Medium" IsAsync="True" /> <Binding ElementName="MainWindow" Path="Fast" /> </PriorityBinding> </TextBlock.Text> </TextBlock>

Cela ressemble { du Multi Binding, sauf quune priorit existe entre les bindings (la plus haute en premier) et que la finalit est une unique valeur, pas une valeur composite. Il ny a pas non plus de convertisseur global, mais rien ninterdit den dfinir au niveau de chaque binding (qui sont eux des bindings normaux , ceux utiliss ici ntant donc que des exemples). On note malgr tout une spcificit, la prsence de IsAsync dans les binding lents. Cela nest pas obligatoire mais sans cette indication sur les sources lentes le Priority Binding perdrait tout son charme. En effet, Xaml tant interprt dans lordre dcriture, le premier binding rencontr serait celui de plus haute priorit mais le plus lent { obtenir. Lapplication se bloquerait jusqu{ lobtention de la valeur. Une fois celle-ci acquise, comme elle est de plus haut niveau, les deux autres seraient ignores. Cest donc tout lintrt du montage qui tomberait { leau sans la magie du multi-threading que IsAsynch ajoute automatiquement ( condition de prciser cette option). La question pige est de savoir pourquoi IsAsync est une option au lieu dtre systmatique. On rpondra quil sagit de souplesse car cest au dveloppeur de dcider. Une autre question est de savoir si le dernier binding doit ou non avoir loption IsAsynch true ou pas Si la valeur est rellement rapide { obtenir je vous conseille de ne pas utiliser loption sur le dernier binding. Mais si le dernier binding, sens tre le plus rapide, peut lui aussi prendre un peu de temps, pour viter de figer lapplication il semble naturel de le mettre en IsAsynch true aussi. Dans ce cas cela signifie que pendant un certain laps de temps il ny aura aucun affichage du tout pour le TextBlock (ou tout autre objet utilisant le mme mcanisme). Cela peut tre satisfaisant comme cela peut ne pas tre acceptable Dans ce dernier cas il faudra alors rajouter un nouveau binding de priorit encore plus basse mais capable de fournir immdiatement une valeur. Il naura alors pas loption IsAsynch true. A moins que Non, il faut malgr tout que la chane sarrte { moment o un autre, mais jentrevois que dans certaines situations ce choix puisse devenir dlicat, voire stratgique

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

74

Les proprits de tous les bindings

aml nest quun langage de description qui est interprt et dont la finalit est linstanciation dobjets ayant des relations entre eux. Cela veut dire que tout ce qui scrit en Xaml peut scrire en code C# par exemple, rien quen instanciant et en initialisant les bons objets dans le bon ordre et en crant les relations ncessaires entre eux. Il nest bien sr pas question de programmer de cette faon ! Mais il faut avoir conscience que toute balise Xaml cache derrire elle une instance dune classe. Cela est vrai aussi pour le Binding. Et qui dit classe et instance, dit proprits et mthodes. Les premires sont accessibles en Xaml, les secondes ne le sont que par code. Il est ainsi parfois ncessaire de rcuprer en C# lobjet correspondant { une balise ou un binding pour accder aux mthodes quil expose. Dans cet article nous nous intressons uniquement au Binding. Les mthodes de la classe Binding sont plutt rserves un usage interne du Framework ou certains bricolages que je prfre de pas imaginer Les proprits de la classe Binding sont en revanche manipulables en Xaml et concentrent toutes les options qui permettent de faonner un lien. Il est intressant de noter au passage que lavnement dun langage descriptif comme Xaml donne aux proprits un rle central qui tranche avec les langages de programmation des gnrations prcdentes qui donnaient encore la priorit aux mthodes. Cest un glissement progressif, du plaisir5, je ne sais pas, mais vers le descriptif et le fonctionnel, cela est certain. Voici un rcapitulatif des principales proprits des Bindings et leur signification. Une grande partie a fait lobjet dexemples dans le prsent article. Pour les autres, cette liste attirera votre attention et vous donnera envie (je lespre) den savoir plus ! Jai ajout des liens vers des informations complmentaires lorsque cela simposait (par exemple vers la dfinition complte de la syntaxe XPath).

Les cinphiles auront not lastucieuse rfrence au film de Robbe-Grillet de 1974

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

75

Proprit BindingGroupName

BindsDirectlyToSource

Converter ConvertCulture ConverterParameter ElementName

FallbackValue IsAsync

Mode NotifyOnSourceUpdated NotityOnTargetUpdated Path RelativeSource Source

StringFormat

TargetNullValue UpdateSourceExceptionFilter

UpdateSourceTrigger

ValidatesOnDataError ValidateOnExceptions ValidationRules

Description Spcifie le nom de BindingGroup. Les BindingGroups ajouts dans WPF dernirement (3.5sp1) simplifient par exemple la gestion des validations. Voir : http://msdn.microsoft.com/frfr/library/system.windows.data.binding_members.aspx Lorsquon utilise une source drivant de DataSourceProvider, en plaant cette proprit { true on cr un lien avec lobjet provider plutt quavec ses donnes. Permet de spcifier le convertisseur utiliser. Permet dindiquer et de forcer la culture que le convertisseur doit utiliser. Le paramtre optionnel pass au convertisseur. Le nom de llment quand on se lie { un lment dans la mme porte Xaml. Ne peut pas tre utilis si RelativeSource ou Source est dj dfini. La valeur utiliser quand le binding rencontre une erreur. A utiliser sur des binding lents afin que la rcupration de la valeur soit effectue automatiquement dans un thread darrire plan non bloquant. Direction et signification du Binding (voir les diffrents modes expliqus dans cet article : OneWay, TwoWay, OneTime, ) Force le dclenchement de lvnement SourceUpdated ds quune valeur est transfre de la cible vers la source. Force le dclenchement de lvnement TargetUpdated quand la cible est mise jour depuis la valeur source. Indique la proprit source Permet de fixer la source de faon relative la cible (voir les exemples dans cet article sur le Binding Relatif). Pointe lobjet qui doit tre considr comme la source du binding. Ne peut pas tre utilis si ElementName ou RelativeSource le sont. Ajout dans 3.5sp1 permet le passage dune chane de format vitant parfois lcriture dun convertisseur (voir exemple dans larticle). Ajout dans 3.5sp1 indique la valeur utiliser si la source est nulle. Permet de grer les exceptions du moteur du binding. Il faut alors associer un ExceptionValidationRule au binding (voir http://msdn.microsoft.com/frfr/library/system.windows.controls.exceptionvalidationrule.aspx ) Timing de la mise jour de la source (voir les exemples de larticle). Valeurs possible : Default, PropertyChanged, LostFocus et Explicit. Ajout dans 3.5sp1 utilise un IDataErrorInfo au moment de la validation des donnes. Ajout dans 3.5sp1 permet de traiter les exceptions du binding comme des violations des rgles de validation. Collection de rgles qui permettent de valider les valeurs gnralement les saisies de lutilisateur.

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

76

XPath

Requte XPath qui retourne la valeur source utiliser lorsque la source est de type XML. La syntaxe peut tre bien plus complexe que celle utilise dans les exemples de cet article. Voir MSDN : http://msdn.microsoft.com/frfr/library/ms256471(VS.80).aspx

Conclusion
Le binding, cet inconnu Prsent dans des dizaines de tutoriaux, et pourtant Ce qui me semble essentiel nest que trs rarement trait : comment sen servir correctement et en viter les piges bien rels. Les tutoriaux et leurs dmos sont toujours bien lisses . Tout fonctionne si on suit la recette . La ralit est bien plus nuance simplement parce que lcriture dune application mme de taille modeste nest pas un long fleuve tranquille. Erreurs de conception quil faut corriger, changement de design de dernire minute, ajouts de fonctionnalits au fil de lcriture, analyse trop succincte (quelle analyse au fait ? ils sont o les documents ?), etc, etc Et dans cette situation prcise quest la ralit, des tas de difficults plus ou moins grandes apparaissent. Mais on en parle que fort peu. Certainement parce que toute dmo, tout tutor a avant tout valeur de propagande et que jamais une publicit ne vous parlera de faon relative du produit, il ne peut qutre beau, facile { utiliser, pratique et faire de vous un hros au quotidien (Microsoft et Borland on mme communiqu un temps sur cette image de super hros totalement ringarde mon got, heureusement le premier na pas insist longtemps et le second est mort, ceci expliquant en partie cela ? ). Dvelopper professionnellement nest pas une simple transcription dune dmo ou dun cours dcole ding. On est souvent plus proche dIndiana Jones couvert de vase se dbrouillant seul dans des marcages putrides et farcis de btes bizarres que dun Tom Cruise tout propre agitant ses datagloves dernier modle devant des crans virtuels dans Minority Report ! Heureusement, tel un super hros je viens votre secours ! (comme lcriraient mes filles : LOL MDR !) Olivier Dahan. Odahan@e-naxos.com http://www.e-naxos.com/blog

Olivier Dahan. Odahan@e-naxos.com. Dot.Blog : www.e-naxos.com/blog

77