Partager via


Modèles WeakEvent

Mise à jour : novembre 2007

Dans les applications types, il est possible que les gestionnaires joints aux sources d'événement ne soient pas détruits dans la coordination avec l'objet Listener qui a joint le gestionnaire à la source. Cette situation peut générer des fuites de mémoire. Windows Presentation Foundation (WPF) introduit un modèle de design particulier qui peut être utilisé pour traiter ce problème en fournissant une classe de gestionnaire dédiée pour des événements particuliers et en implémentant une interface dans les écouteurs de l'événement. Ce modèle de design s'appelle le modèle WeakEvent.

Pourquoi implémenter le modèle WeakEvent ?

L'écoute des événements peut générer des fuites de mémoire. La technique standard pour écouter un événement consiste à utiliser la syntaxe du langage qui lie un gestionnaire à un événement dans une source. Par exemple, dans C#, cette syntaxe est source.SomeEvent += new SomeEventHandler(MyEventHandler).

Cette technique crée une référence forte entre la source d'événement et l'écouteur d'événement. Normalement, la liaison d'un gestionnaire d'événements pour un écouteur amène l'écouteur à avoir une durée de vie d'objet qui est affectée par la durée de vie d'objet de la source (à moins que le gestionnaire d'événements soit supprimé explicitement). Cependant, dans certains cas, vous pouvez vouloir contrôler la durée de vie d'objet de l'écouteur uniquement par d'autres facteurs, tels que son appartenance actuelle à l'arborescence visuelle de l'application, et non par la durée de vie de la source. Chaque fois que la durée de vie d'objet de la source est plus longue que celle de l'écouteur, le modèle d'événement normal génère une fuite de mémoire ; l'écouteur reste actif plus longtemps que prévu.

Le modèle WeakEvent est conçu pour résoudre ce problème de fuite de mémoire. Le modèle WeakEvent peut être utilisé chaque fois qu'un écouteur doit s'inscrire pour un événement et que l'écouteur ne sait pas explicitement quand il doit s'inscrire, et chaque fois que la durée de vie d'objet de la source est plus longue que la durée de vie "utile" de l'écouteur. (La notion d'"utilité" dépend de votre appréciation.) Le modèle WeakEvent permet à l'écouteur de s'inscrire pour l'événement et de recevoir l'événement sans affecter du tout les caractéristiques de durée de vie de l'écouteur. En fait, la référence implicite de la source ne compte pas lorsque vous décidez si l'écouteur est prêt pour le garbage collection. La référence est une référence faible, d'où le nom du modèle WeakEvent et les API connexes. L'écouteur peut être récupéré par le garbage collector ou détruit, et la source peut continuer sans conserver des références de gestionnaire non-collectable à un objet détruit.

Qui doit implémenter le modèle WeakEvent ?

L'implémentation du modèle WeakEvent concerne principalement les auteurs de contrôle. Cela s'explique par le fait qu'en tant qu'auteur, vous êtes principalement responsable du comportement et de la relation contenant-contenu de votre contrôle et de l'impact qu'il a sur les applications dans lesquelles il est inséré. Cela inclut le comportement de durée de vie d'objet de contrôle, en particulier la gestion du problème de fuite de mémoire décrit.

Certains scénarios se prêtent fondamentalement à l'application du modèle WeakEvent. La liaison de données, où généralement un objet source qui est une source de données est complètement indépendant d'un objet d'écouteur, qui est une cible d'une liaison, fait partie de ces scénarios. Le modèle WeakEvent est déjà appliqué pour biens des aspects de la liaison de données WPF pour ce qui concerne la manière d'implémenter les événements.

Comment implémenter le modèle WeakEvent

L'implémentation du modèle WeakEvent comporte trois aspects :

  • Dérivation d'un gestionnaire de WeakEventManager.

  • Implémentation de l'interface IWeakEventListener dans une classe qui veut inscrire les écouteurs pour l'événement faible sans générer une référence forte à la source.

  • Lorsque vous inscrivez des écouteurs, n'utilisez pas l'ajout conventionnel et supprimez les accesseurs de l'événement dans lequel vous voulez que l'écouteur utilise le modèle. À la place, utilisez les implémentations "AddListener" et "RemoveListener" dans le WeakEventManager dédié à cet événement.

WeakEventManager

En général, vous créez des classes de gestionnaire dans une relation 1:1 dans les événements qui implémentent le modèle. Par exemple, si vous utilisez un événement Spin, vous devez dériver une classe SpinEventManager sous la forme du gestionnaire d'événements faible dédié de l'événement. Si l'événement existe dans plusieurs classes de source, qu'il a le même comportement général dans chaque classe et qu'il partage le type de donnée d'événement, le même gestionnaire peut être utilisé pour chacune des classes.

La liste de contrôle d'implémentation de la dérivation depuis la classe WeakEventManager consiste à substituer deux méthodes virtuelles en exposant plusieurs autres membres dont les noms ne sont pas gouvernés spécifiquement par un modèle virtuel, mais qui doivent exister néanmoins. Les substitutions sont utilisées pour initialiser ou terminer le mode de remise d'événement par l'infrastructure WPF. Les autres membres sont nécessaires pour fournir la fonctionnalité afin que vos propres implémentations IWeakEventListener puissent utiliser WeakEventManager pour lier des écouteurs à l'événement.

Pour des remarques d'implémentation détaillées pour la dérivation depuis WeakEventManager, consultez « Remarques à l'attention des héritiers » dans la rubrique de référence WeakEventManager.

IWeakEventListener

Une classe d'implémentation IWeakEventListener n'a qu'une seule fonction : implémenter la méthode d'interface ReceiveWeakEvent. L'implémentation de ReceiveWeakEvent doit être une implémentation centralisée qui dirige toute référence d'événement existant dans la classe vers le WeakEventManager approprié.

Pour des remarques détaillées au sujet de l'implémentation de l'interface IWeakEventListener, consultez « Remarques à l'attention des héritiers » dans la rubrique de référence de la méthode ReceiveWeakEvent.

Liaison d'écouteurs

Supposons que vous utilisez l'événement ClockwiseSpin (défini par Spinner) qui correspond à un événement classique. Pour utiliser le modèle de cet événement, vous utilisez une classe ClockwiseSpinEventManager existante dérivée de WeakEventManager ou vous l'implémentez vous-même. Si vous utilisez une classe d'écouteur SpinListener qui veut être un écouteur, la technique classique (sans utiliser le modèle) pour lier le gestionnaire consiste à utiliser la syntaxe + = :

spinnerInstance.ClockwiseSpin += new EventHandler(MyOnCWSpinHandler);

Cependant, si vous utilisez une classe qui implémente IWeakEventListener et qui tient compte de l'événement ClockwiseSpin et de son gestionnaire dans l'implémentation, la syntaxe à utiliser à la place pour le modèle WeakEvent est :

ClockwiseSpinEventManager.AddListener(spinnerInstance, this);

Ensuite, votre gestion logique de cet événement est spécifiée dans l'un des cas de l'implémentation ReceiveWeakEvent dans votre classe, mais pas comme un gestionnaire classique basé sur les délégués.

Implémentation du modèle pour les événements externes

Un aspect intéressant du modèle WeakEvent réside dans le fait que vous pouvez implémenter le modèle par rapport à un événement qui ne fait pas partie de votre base de code. Du point de vue de la source, la manière de lier ces gestionnaires à son événement ne change pas et elle est contrôlée par WeakEventManager. Il suffit de définir un WeakEventManager pour cet événement, puis de tenir compte de cet événement dans la logique ReceiveWeakEvent dans un écouteur qui veut utiliser le modèle pour écouter l'événement.

Voir aussi

Concepts

Vue d'ensemble des événements routés

Vue d'ensemble de la liaison de données

Référence

WeakEventManager

IWeakEventListener