Partager via


Modèles d'événement faible

Il est possible que les gestionnaires attachés à des sources d'événement dans les applications ne soient pas détruits en coordination avec l'objet écouteur qui a attaché le gestionnaire à la source. Cette situation peut entraîner des fuites de mémoire. Windows Presentation Foundation (WPF) introduit un modèle de conception qui permet de traiter ce problème en fournissant une classe de gestionnaire dédiée pour des événements particuliers et en implémentant une interface sur les écouteurs de ces événements. Ce modèle de conception est appelé modèle d'événement faible.

Pourquoi implémenter le modèle d'événement faible ?

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 attache un gestionnaire à un événement d'une source. Par exemple, en 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. En général, lorsque vous attachez un gestionnaire d'événements pour un écouteur, la durée de vie d'objet de l'écouteur est influencée par celle de la source (à moins que le gestionnaire d'événement ne soit explicitement supprimé). Toutefois, dans certains cas, il peut s'avérer utile de contrôler la durée de vie d'objet de l'écouteur par des facteurs tels que son appartenance actuelle à l'arborescence d'éléments visuels de l'application, et non pas 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 d'événement faible est conçu pour résoudre ce problème de fuite de mémoire. Il peut être utilisé chaque fois qu'un écouteur doit s'inscrire pour un événement et qu'il ne sait pas explicitement quand l'inscription doit être annulée. Il peut également être employé chaque fois que la durée de vie d'objet de la source dépasse la durée de vie d'objet utile de l'écouteur. (Dans ce cas, c'est vous qui déterminez la notion d'utilité.) Le modèle d'événement faible permet à l'écouteur de s'inscrire pour l'événement et de le recevoir sans affecter, de quelque manière que ce soit, les caractéristiques de durée de vie d'objet de l'écouteur. En fait, la référence implicite de la source ne détermine pas si l'écouteur est disponible pour le garbage collection. La référence est une référence faible, d'où le nom donné au modèle et aux APIs associées. 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 d'événement faible ?

L'implémentation du modèle d'événement faible concerne principalement les auteurs de contrôle. En tant qu'auteur de contrôle, vous êtes principalement responsable du comportement et de la relation contenant-contenu de votre contrôle, ainsi que de son impact sur les applications dans lesquelles il est inséré. Cela inclut le comportement de durée de vie d'objet du contrôle, et notamment la gestion du problème de fuite de mémoire décrit.

Certains scénarios se prêtent par nature à l'application du modèle d'événement faible. La liaison de données fait partie de ces scénarios. Dans une liaison de données, l'objet source est en général complètement indépendant de l'objet écouteur, qui est une cible de la liaison. Le modèle d'événement faible s'applique déjà à nombreux aspects de la liaison de données WPF quant la façon dont les événements sont implémentés.

Comment implémenter le modèle d'événement faible ?

L'implémentation du modèle d'événement faible 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. Utilisez à la place les implémentations d'AddListener et de RemoveListener dans le WeakEventManager dédié à cet événement.

WeakEventManager

Pour implémenter le modèle d'événement faible, vous créez généralement une classe de gestionnaire avec une relation 1:1 à l'événement. Par exemple, si vous utilisez un événement nommé Spin, vous devez créer une classe SpinEventManager qui représente le gestionnaire d'événements faibles dédié à l'événement. Si l'événement existe dans plusieurs classes, a généralement le même comportement dans chaque classe et partage le type de donnée d'événement, le même gestionnaire peut être utilisé pour chaque événement.

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

Pour plus d'informations sur la dérivation à partir de WeakEventManager, consultez la section « Remarques à l'attention des héritiers » dans la rubrique de référence WeakEventManager.

IWeakEventListener

L'interface IWeakEventListener a une méthode d'interface unique nommée 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 plus d'informations sur l'implémentation de l'interface IWeakEventListener, consultez la section « Remarques à l'attention des implémenteurs » dans la rubrique de référence relative à la méthode ReceiveWeakEvent.

Attachement d'écouteurs

Supposons que vous utilisiez l'événement ClockwiseSpin (défini par un type Spinner) qui correspond à un événement classique. Si vous utilisez une classe d'écouteur SpinListener comme écouteur, la technique classique (n'ayant pas recours au modèle d'événement faible) pour attacher le gestionnaire consiste à employer l'opérateur + :

spinnerInstance.ClockwiseSpin += new EventHandler(MyOnCWSpinHandler);

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

ClockwiseSpinEventManager.AddListener(spinnerInstance, this);

Votre logique de gestion de cet événement est spécifiée dans l'un des cas de l'implémentation de 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 d'événement faible réside dans le fait que vous pouvez l'implémenter par rapport à un événement ne faisant pas partie de votre base de code. Du point de vue de la source, la manière d'attacher les gestionnaires à leur événement ne change pas ; elle 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 de ReceiveWeakEvent dans tout écouteur souhaitant utiliser le modèle d'événement faible pour écouter l'événement.

Voir aussi

Référence

WeakEventManager

IWeakEventListener

Concepts

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

Vue d'ensemble de la liaison de données