Routed Event :
Ce qui est difficile pour moi qui vient du monde ASP.NET, c’est le nombre de nouveaux concepts qu’il faut apprendre avant de maîtriser WPF. En effet, il y a plusieurs concepts nouveaux en WPF. Les dependency property (qui servent pour le databinding, le styling,…) mais également les RoutedEvents et les RoutedCommand. En effet, WPF n’utilise pas le système standard des événements mais une version plus puissante. Pour qu’un objet puisse avoir la possibilité de bénéficier de ces nouvelles fonctionnalités, il doit obligatoirement dérivée de la classe UIElement.
Généralement, vous utilisez les Routed Event sans vous en rendre compte. Par exemple, vous ajoutez un bouton dans un objet Windows, vous le nommez MyButton, vous double-cliquez sur ce bouton, il va créer tout ce qu’il vous faut pour que vous puissiez créer l’action que vous désirez déclencher lors de l’évènement click de l’élément bouton. Vous ne verrez alors aucune différence entre WPF et Winforms ou ASP.NET.
Prenons le bouton XAML :
![]()
La déclaration en XAML pour se « raccorder » à l’événement est juste une propriété Click du contrôle Bouton. En fait, ce raccordement se trouve dans un « compile-time-generated » de la classe partiel de votre Windows (en gros le framework fait tout pour que ce soit transparent pour vous). Pour visualiser tous ces appels « automatiques », faites un clique droit sur la méthode InitializeComponent() de votre Window. Si vous descendez un peu vous verrez les lignes suivantes :

La classe partielle est générée à partir du XAML lors de la compilation et contient tous les éléments XAML qu’a besoin le « design-time compilator ».
Si nous regardons de plus près le code de cette classe partiel, le Click handler ressemble à ceci :
![]()
Ce qui ressemble fortement à ce que vous connaissez déjà dans le monde .NET. La seule chose différente est que vous n’utilisez plus EventArg comme type d’argument mais RoutedEventArgs.
Mais qu’y a-t-il de si différent ? Avant de vous expliquer cela, vous devez comprendre la composition des éléments du modèle WPF.
WPF, structure en Arbre :
Si vous démarrez un nouveau projet WPF, vous allez directement vous retrouver avec un code qui ressemble à ceci :

Chaque élément représente une Runtime instance correspondant à un type .NET, et nous remarquons la structure en arbre (logical tree) qui impose une hiérarchie entre les éléments. De plus, la plupart des éléments en WPF sont dit soit ContentControl ou ItemsControl .Ce qui veut dire qu’ils peuvent comprendre des éléments enfants.
Par exemple, un Bouton est un ContentControl , il peut avoir une hiérarchie complexe d’enfant en dessous de lui. Nous pourrions alors écrire ceci :

L’application ressemblerait alors à quelque chose du genre :

Comme vous en doutez, l’arborescence de cette structure peut devenir extrêmement complexe. Mais n’oubliez pas qu’en WPF tout ce que vous voyez n’est pas nécessairement ce que vous avez au Runtime.
Ci-dessous, l’arbre logique de notre bouton contenant un stackpanel comprenant lui-même une image et un textblock.

Vous pouvez remarque que l’élément windows (EventsWindows) englobe son contenu dans un Border et un AdornerDecorator et présente le contenu à l’intérieur d’un ContentPresenter. Le bouton fait de même en englobant son contenu avec un objet ButtonChrome et présente son contenu dans un ContentPresenter.
Quand je clique sur le bouton, je pourrais ne pas cliquer du tout sur l’élément Bouton mais sur un de ses enfants dans l’arbre logique, peut-être même un qui n’est même pas dans cette structure en arbre (ButtonChrome). Par exemple, je clique avec ma souris sur le coin supérieur de l’image contenu dans le bouton. Cette action se manifeste comme un évènement MouseLeftButtonDown à l’intérieur de l’élément image ; mais nous voudrions que celui-ci soit transmis comme évènement click au niveau de l’élément bouton. C’est ici que rentre en jeux les RoutedEvents.
Les évènements routés :
Bien comprendre la structure en arbre des éléments dans WPF est primordial pour bien comprendre les routed events. En effet, les routed events sont routées par défaut sur cette structure en arbre. Ils supportent également les RoutingStrategy de type Bubble, Tunnel et Direct.
Bubble :
Bubble est le plus commun, l’évènement se propagera vers le haut de la structure à partir de l’élément source jusqu’à ce qu’il soit géré où qu’il ait atteint l’élément racine. Cela vous permet de gérer un évènement par un objet qui se trouve plus éloigné dans la structure que votre élément source. Par exemple, vous pourriez attacher un Button.Click handler sur l’élément Grid compris dans l’objet Button lui-même. Les évènements Bubble ont juste leur nom qui indique leur action (par exemple, MouseDown).
L’évènement Tunnel, lui, part de l’élément racine et traverse vers le bas les éléments de la structure jusqu’à ce qu’il soit pris en compte où qu’il atteigne l’élément source de l’évènement. Cela permet d’intercepter des évènements en amont et de le manipuler avant que celui-ci n’atteignent l’élément source. Les évènements Tunnel sont généralement nommés par le préfixe Preview par convention (PreviewMouseDown).
Les évènements Direct, eux, se comporte de la même manière que les évènements normaux dans le Framework .NET. Le seul handler possible pour ce type d’évènement est un delegate qui souscrit à cet évènement.
Généralement, pour chaque évènement Tunnel correspond un évènement Bubble. Dans ce cas, l’évènement Tunnel est déclenché en premier ; ils commencent de l’élément racine et descend vers l’élément source en cherchant un handler. Une fois qu’il a été intercepté ou a atteint l’élément source, le Bubble event correspondant est lancé. Partant de l’élément source et remontant vers le haut de la structure cherchant un handler.
A noter qu’un évènement Bubble ou Tunnel ne se stoppent pas parcequ’un EventHandler a été appelé. Si vous voulez stopper un évènement Bubble ou Tunnel, vous devez marquer l’évènement comme « handled » en utilisant l’argument évènement qui lui est passé.

Le fait que l’évènement stoppe lorsque celui-ci est marqué «handled » n’est pas totalement vrai. En réalité le processus continue en arrière scène et vous pourriez intercepter de nouveaux cet évènement en « overridant » UIElement.AddHandler method qui possède un flag permettant de continué la propagation de l’évènement, c’est-à-dire « Appelle moi-même si l’évènement est marqué comme handled ».
Voici comment spécifier ce flag :
![]()
Le premier paramètre est le RoutedEvent que vous voulez manipuler, le second est une fonction delegate à la méthode qui manipulera l’évènement (qui devra posséder une signature correcte pour le delegate de cet évènement), le troisième paramètre indique si oui ou non vous voulez être notifié (même si un autre handler a marqué cet évènement comme « handled »). L’élément du quel vous appelez AddHandler est celui qui surveillera l’évènement pendant que celui-ci traverse la structure en arbre.
Routed Events et Composition :
Prenons comme exemple l’évènement Click du Bouton ci-dessus. Lorsque nous cliquons sur l’image qui se trouvent dans cet élément bouton. Comme mentionné ci-dessus, un utilisateur va initier un évènement Click avec un MouseLeftButtonDown event sur certain des éléments enfant dans cette structure en arbre de votre bouton (comme l’élément image dans notre cas du dessus).
Quand le MouseLeftButtonDown évènement se déclenche à partir de l’élément Image, l’évènement PreviewMouseLeftDown commence de l’élément root et se propage jusqu’à l’élément Image. Si personne n’a manipulé cet évènement et a marqué l’évènement comme « handled », un évènement MouseLeftDown de type « bubble » sera propagé depuis l’élément image jusqu’à l’élément bouton. Le bouton manipule alors cet évènement, marque l’évènement comme handled et propage alors un évènement Click.
Attached Events :
Pour permettre à un élément de manipuler un évènement qui est déclaré dans un élément différent. WPF supporte les Attached Events. Attached Event sont des RoutedEvent qui supporte une déclaration d’un handler dans un autre type que celui où l’évènement est propagé. Par exemple, un élément Grid qui écouterait l’évènement Click de l’élément bouton.

Le code généré par la classe partiel compile-time

Plus d’information :
Si vous voulez créer vos propre RoutedEvent, je vous invite à lire cet article très intéressant sur les RoutedEvent : http://blogs.developpeur.org/raptorxp/archive/2007/07/18/wpf-comprendre-les-routed-events.aspx
En conclusion :
Vous savez maintenant ce qu’est un RoutedEvent, cette notion est une notion de base de l’environnement WPF et il était un pré requis à connaître avant de rentrer dans les détails du Composite Application Guidance. Si vous avez des questions, des suggestions et/ou des compléments d’information, n’hésitez-pas commenter cet article.
1 Response to Composite Application Guidance WPF/Silverlight - Requis : RoutedEvent - 2
admin
October 13th, 2009 at 10:34 am
Un autre lien pour encore mieux comprendre les RoutedEvents : http://www.codeproject.com/KB/WPF/VMCommanding.aspx