Modèles d'événement faibleWeak Event Patterns

Dans les applications, il est possible que les gestionnaires qui sont attachés à des sources d’événements ne sont pas détruits en coordination avec l’objet écouteur qui joint le gestionnaire à la source.In applications, it is possible that handlers that are attached to event sources will not be destroyed in coordination with the listener object that attached the handler to the source. Cette situation peut conduire à des fuites de mémoire.This situation can lead to memory leaks. Windows Presentation Foundation (WPF)Windows Presentation Foundation (WPF) introduit un modèle de conception qui peut être utilisé pour résoudre 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 cet événement. introduces a design pattern that can be used to address this issue, by providing a dedicated manager class for particular events and implementing an interface on listeners for that event. Ce modèle de conception est appelé le du modèle d’événement faible.This design pattern is known as the weak event pattern.

Pourquoi implémenter le modèle d’événement faible ?Why Implement the Weak Event Pattern?

L’écoute des événements peut provoquer des fuites de mémoire.Listening for events can lead to memory leaks. La technique standard pour écouter un événement est d’utiliser la syntaxe spécifique au langage qui attache un gestionnaire à un événement sur une source.The typical technique for listening to an event is to use the language-specific syntax that attaches a handler to an event on a source. Par exemple, en c#, cette syntaxe est : source.SomeEvent += new SomeEventHandler(MyEventHandler).For example, in C#, that syntax is: source.SomeEvent += new SomeEventHandler(MyEventHandler).

Cette technique crée une référence forte à partir de la source d’événements à l’écouteur d’événements.This technique creates a strong reference from the event source to the event listener. En règle générale, attachement d’un gestionnaire d’événements pour un écouteur de provoque l’écouteur ont une durée de vie est influencée par la durée de vie de la source (sauf si le Gestionnaire d’événements est supprimé explicitement).Ordinarily, attaching an event handler for a listener causes the listener to have an object lifetime that is influenced by the object lifetime of the source (unless the event handler is explicitly removed). Toutefois, dans certaines circonstances, vous pouvez la durée de vie de l’écouteur à être contrôlés par d’autres facteurs, tels que si elle appartient actuellement à l’arborescence d’éléments visuels de l’application et non par la durée de vie de la source.But in certain circumstances, you might want the object lifetime of the listener to be controlled by other factors, such as whether it currently belongs to the visual tree of the application, and not by the lifetime of the source. Chaque fois que la durée de vie source s’étend au-delà de la durée de vie de l’écouteur, le modèle d’événement normal entraîne une fuite de mémoire : l’écouteur est maintenue actif plus longtemps que prévu.Whenever the source object lifetime extends beyond the object lifetime of the listener, the normal event pattern leads to a memory leak: the listener is kept alive longer than intended.

Le modèle d’événement faible est conçu pour résoudre ce problème de fuite de mémoire.The weak event pattern is designed to solve this memory leak problem. Le modèle d’événement faible peut être utilisé chaque fois qu’un écouteur doit s’inscrire pour un événement, mais l’écouteur ne sait pas explicitement quand annuler l’inscription.The weak event pattern can be used whenever a listener needs to register for an event, but the listener does not explicitly know when to unregister. Le modèle d’événement faible peut également servir à chaque fois que la durée de vie de la source dépasse la durée de vie utile de l’écouteur.The weak event pattern can also be used whenever the object lifetime of the source exceeds the useful object lifetime of the listener. (Dans ce cas, utile est déterminée par vous.) Le modèle d’événement faible permet à l’écouteur à inscrire et recevoir l’événement sans affecter les caractéristiques de durée de vie d’objet de l’écouteur en aucune façon.(In this case, useful is determined by you.) The weak event pattern allows the listener to register for and receive the event without affecting the object lifetime characteristics of the listener in any way. En effet, la référence implicite à partir de la source ne détermine pas si l’écouteur est éligible pour le garbage collection.In effect, the implied reference from the source does not determine whether the listener is eligible for garbage collection. La référence est une référence faible, d'où le nom de modèle d’événement faible et le APIAPIs.The reference is a weak reference, thus the naming of the weak event pattern and the related APIAPIs. L’écouteur peut être le garbage collector ou détruit, et la source peut continuer sans conservation des références de gestionnaire non-collectable à un objet détruit.The listener can be garbage collected or otherwise destroyed, and the source can continue without retaining noncollectible handler references to a now destroyed object.

Qui doit implémenter le modèle d’événement faible ?Who Should Implement the Weak Event Pattern?

Il est intéressant principalement pour les auteurs de contrôle de l’implémentation du modèle d’événement faible.Implementing the weak event pattern is interesting primarily for control authors. En tant qu’auteur de contrôle, vous devez en grande partie le comportement et la relation contenant-contenu de votre contrôle et l’impact sur les applications dans lequel elle est insérée.As a control author, you are largely responsible for the behavior and containment of your control and the impact it has on applications in which it is inserted. Cela inclut le comportement de durée de vie l’objet contrôle, notamment la gestion du problème de fuite de mémoire décrit.This includes the control object lifetime behavior, in particular the handling of the described memory leak problem.

Certains scénarios, par nature, se prêtent à l’application du modèle d’événement faible.Certain scenarios inherently lend themselves to the application of the weak event pattern. Un tel scénario est la liaison de données.One such scenario is data binding. Dans la liaison de données, il est courant de l’objet source soit complètement indépendante de l’objet de l’écouteur, qui est une cible d’une liaison.In data binding, it is common for the source object to be completely independent of the listener object, which is a target of a binding. Nombreux aspects de WPFWPF déjà une liaison de données ont le modèle d’événement faible appliqué dans la façon dont les événements sont implémentés.Many aspects of WPFWPF data binding already have the weak event pattern applied in how the events are implemented.

Comment implémenter le modèle d’événement faibleHow to Implement the Weak Event Pattern

Il existe trois façons d’implémenter le modèle d’événement faible.There are three ways to implement weak event pattern. Le tableau suivant répertorie les trois approches et fournit quelques conseils pour l’utilisation de chacune.The following table lists the three approaches and provides some guidance for when you should use each.

ApprocheApproach Quand mettre en œuvreWhen to Implement
Utiliser une classe de gestionnaire d’événement faible existanteUse an existing weak event manager class Si l’événement que vous voulez vous abonner a correspondante WeakEventManager, utilisez le Gestionnaire d’événement faible existant.If the event you want to subscribe to has a corresponding WeakEventManager, use the existing weak event manager. Pour obtenir la liste des gestionnaires d’événement faible qui sont inclus dans WPF, consultez la hiérarchie d’héritage dans le WeakEventManager classe.For a list of weak event managers that are included with WPF, see the inheritance hierarchy in the WeakEventManager class. Toutefois, notez qu’il n’y a relativement peu gestionnaires d’événement faible qui sont inclus dans WPF, vous devrez probablement choisir l’une des autres approches.Note, however, that there are relatively few weak event managers that are included with WPF, so you will probably need to choose one of the other approaches.
Utiliser une classe de gestionnaire d’événement faible génériqueUse a generic weak event manager class Utilisez un type générique WeakEventManager<TEventSource,TEventArgs> lorsque existant WeakEventManager est non disponible, vous souhaitez un moyen simple d’implémenter, et vous ne sont pas concernées par l’efficacité.Use a generic WeakEventManager<TEventSource,TEventArgs> when an existing WeakEventManager is not available, you want an easy way to implement, and you are not concerned about efficiency. Le type générique WeakEventManager<TEventSource,TEventArgs> est moins efficace que d’un gestionnaire d’événements faibles existantes ou personnalisées.The generic WeakEventManager<TEventSource,TEventArgs> is less efficient than an existing or custom weak event manager. Par exemple, la classe générique fait plus de réflexion pour découvrir l’événement étant donné le nom de l’événement.For example, the generic class does more reflection to discover the event given the event's name. En outre, le code pour inscrire l’événement à l’aide de l’objet générique WeakEventManager<TEventSource,TEventArgs> est plus détaillé qu’utilisant un existant ou personnalisé WeakEventManager.Also, the code to register the event by using the generic WeakEventManager<TEventSource,TEventArgs> is more verbose than using an existing or custom WeakEventManager.
Créer une classe de gestionnaire d’événement faible personnaliséCreate a custom weak event manager class Créer un personnalisé WeakEventManager lorsque existant WeakEventManager n’est pas disponible et que vous souhaitez la meilleure efficacité.Create a custom WeakEventManager when an existing WeakEventManager is not available and you want the best efficiency. L’aide d’un WeakEventManager pour vous abonner à un événement est plus efficace, mais vous n’entraînent pas le coût de l’écriture de code plus au début.Using a custom WeakEventManager to subscribe to an event will be more efficient, but you do incur the cost of writing more code at the beginning.

Les sections suivantes décrivent comment implémenter le modèle d’événement faible.The following sections describe how to implement the weak event pattern. Pour des raisons de cette discussion, de s’abonner à l’événement présente les caractéristiques suivantes.For purposes of this discussion, the event to subscribe to has the following characteristics.

  • Le nom de l’événement est SomeEvent.The event name is SomeEvent.

  • L’événement est déclenché par la EventSource classe.The event is raised by the EventSource class.

  • Le Gestionnaire d’événements a type : SomeEventEventHandler (ou EventHandler<SomeEventEventArgs>).The event handler has type: SomeEventEventHandler (or EventHandler<SomeEventEventArgs>).

  • L’événement passe un paramètre de type SomeEventEventArgs aux gestionnaires d’événements.The event passes a parameter of type SomeEventEventArgs to the event handlers.

À l’aide d’une classe de gestionnaire d’événements existante faibleUsing an Existing Weak Event Manager Class

  1. Gestionnaire de trouver un événement faible existant.Find an existing weak event manager.

    Pour obtenir la liste des gestionnaires d’événement faible qui sont inclus dans WPF, consultez la hiérarchie d’héritage dans le WeakEventManager classe.For a list of weak event managers that are included with WPF, see the inheritance hierarchy in the WeakEventManager class.

  2. Utilisez le nouveau gestionnaire d’événement faible au lieu de la connexion d’événements normaux.Use the new weak event manager instead of the normal event hookup.

    Par exemple, si votre code utilise le modèle suivant pour vous abonner à un événement :For example, if your code uses the following pattern to subscribe to an event:

    source.SomeEvent += new SomeEventEventHandler(OnSomeEvent);  
    

    Modifier le modèle suivant :Change it to the following pattern:

    SomeEventWeakEventManager.AddHandler(source, OnSomeEvent);  
    

    De même, si votre code utilise le modèle suivant pour annuler l’abonnement à un événement :Similarly, if your code uses the following pattern to unsubscribe to an event:

    source.SomeEvent -= new SomeEventEventHandler(OnSome);  
    

    Modifier le modèle suivant :Change it to the following pattern:

    SomeEventWeakEventManager.RemoveHandler(source, OnSomeEvent);  
    

À l’aide de la classe de gestionnaire d’événements générique faibleUsing the Generic Weak Event Manager Class

  1. Utilisez le type générique WeakEventManager<TEventSource,TEventArgs> classe au lieu de la connexion d’événements normaux.Use the generic WeakEventManager<TEventSource,TEventArgs> class instead of the normal event hookup.

    Lorsque vous utilisez WeakEventManager<TEventSource,TEventArgs> pour inscrire les écouteurs d’événements, vous fournissez la source d’événements et EventArgs type que les paramètres de type de la classe et l’appel AddHandler comme indiqué dans le code suivant :When you use WeakEventManager<TEventSource,TEventArgs> to register event listeners, you supply the event source and EventArgs type as the type parameters to the class and call AddHandler as shown in the following code:

    WeakEventManager<EventSource, SomeEventEventArgs>.AddHandler(source, "SomeEvent", source_SomeEvent);  
    

Création d’une classe de gestionnaire d’événements personnalisé faibleCreating a Custom Weak Event Manager Class

  1. Copiez le modèle de classe suivant à votre projet.Copy the following class template to your project.

    Cette classe hérite de la WeakEventManager classe.This class inherits from the WeakEventManager class.

    class SomeEventWeakEventManager : WeakEventManager
    {
    
        private SomeEventWeakEventManager()
        {
    
        }
    
        /// <summary>
        /// Add a handler for the given source's event.
        /// </summary>
        public static void AddHandler(EventSource source, 
                                      EventHandler<SomeEventEventArgs> handler)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            if (handler == null)
                throw new ArgumentNullException("handler");
    
            CurrentManager.ProtectedAddHandler(source, handler);
        }
    
        /// <summary>
        /// Remove a handler for the given source's event.
        /// </summary>
        public static void RemoveHandler(EventSource source, 
                                         EventHandler<SomeEventEventArgs> handler)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            if (handler == null)
                throw new ArgumentNullException("handler");
    
            CurrentManager.ProtectedRemoveHandler(source, handler);
        }
    
        /// <summary>
        /// Get the event manager for the current thread.
        /// </summary>
        private static SomeEventWeakEventManager CurrentManager
        {
            get
            {
                Type managerType = typeof(SomeEventWeakEventManager);
                SomeEventWeakEventManager manager = 
                    (SomeEventWeakEventManager)GetCurrentManager(managerType);
    
                // at first use, create and register a new manager
                if (manager == null)
                {
                    manager = new SomeEventWeakEventManager();
                    SetCurrentManager(managerType, manager);
                }
    
                return manager;
            }
        }
    
    
    
        /// <summary>
        /// Return a new list to hold listeners to the event.
        /// </summary>
        protected override ListenerList NewListenerList()
        {
            return new ListenerList<SomeEventEventArgs>();
        }
    
    
        /// <summary>
        /// Listen to the given source for the event.
        /// </summary>
        protected override void StartListening(object source)
        {
            EventSource typedSource = (EventSource)source;
            typedSource.SomeEvent += new EventHandler<SomeEventEventArgs>(OnSomeEvent);
        }
    
        /// <summary>
        /// Stop listening to the given source for the event.
        /// </summary>
        protected override void StopListening(object source)
        {
            EventSource typedSource = (EventSource)source;
            typedSource.SomeEvent -= new EventHandler<SomeEventEventArgs>(OnSomeEvent);
        }
    
        /// <summary>
        /// Event handler for the SomeEvent event.
        /// </summary>
        void OnSomeEvent(object sender, SomeEventEventArgs e)
        {
            DeliverEvent(sender, e);
        }
    }
    
  2. Remplacez le SomeEventWeakEventManager avec votre propre nom.Replace the SomeEventWeakEventManager name with your own name.

  3. Remplacez les noms de trois décrits précédemment, avec les noms correspondants pour votre événement.Replace the three names described previously with the corresponding names for your event. (SomeEvent, EventSource, et SomeEventEventArgs)(SomeEvent, EventSource, and SomeEventEventArgs)

  4. Définir la visibilité (publique, interne, privée) de la classe de gestionnaire d’événement faible pour la même visibilité que les événements qu’il gère.Set the visibility (public / internal / private) of the weak event manager class to the same visibility as event it manages.

  5. Utilisez le nouveau gestionnaire d’événement faible au lieu de la connexion d’événements normaux.Use the new weak event manager instead of the normal event hookup.

    Par exemple, si votre code utilise le modèle suivant pour vous abonner à un événement :For example, if your code uses the following pattern to subscribe to an event:

    source.SomeEvent += new SomeEventEventHandler(OnSomeEvent);  
    

    Modifier le modèle suivant :Change it to the following pattern:

    SomeEventWeakEventManager.AddHandler(source, OnSomeEvent);  
    

    De même, si votre code utilise le modèle suivant pour annuler l’abonnement à un événement :Similarly, if your code uses the following pattern to unsubscribe to an event:

    source.SomeEvent -= new SomeEventEventHandler(OnSome);  
    

    Modifier le modèle suivant :Change it to the following pattern:

    SomeEventWeakEventManager.RemoveHandler(source, OnSomeEvent);  
    

Voir aussiSee Also

WeakEventManager
IWeakEventListener
Vue d’ensemble des événements routésRouted Events Overview
Vue d’ensemble de la liaison de donnéesData Binding Overview