Gérer et déclencher des événements

Les événements dans .NET Framework sont basés sur le modèle délégué. Le modèle délégué suit le modèle de conception observateur, qui permet à un abonné de s'inscrire pour recevoir des notifications d'un fournisseur. Un émetteur d'événements émet une notification d'événement, et un récepteur d'événements reçoit cette notification et définit une réponse à celle-ci. Cet article décrit les principaux composants du modèle délégué, comment consommer les événements des applications, et comment implémenter des événements dans votre code.

Événements

Un événement est un message envoyé par un objet pour signaler la présence d’une action. L’action peut être provoquée par l’interaction utilisateur, par exemple un clic sur un bouton, ou elle peut résulter d’une autre logique de programme, telle que la modification de la valeur d’une propriété. L’objet qui déclenche l’événement est appelé l’émetteur d’événements. L'émetteur d'événements ne connaît pas l'objet, ni la méthode qui recevront (géreront) les événements qu'il déclenche. L'événement est généralement un membre de l'émetteur d'événements ; par exemple, l'événement Click est membre de la classe Button, et l'événement PropertyChanged est membre de la classe qui implémente l'interface INotifyPropertyChanged.

Pour définir un événement, vous utilisez le mot clé C# event Visual Basic Event dans la signature de votre classe d'événements, puis vous spécifiez le type de délégué pour l'événement. Les délégués sont décrits dans la section suivante.

En général, pour déclencher un événement, ajoutez une méthode qui est marquée comme protected et virtual (C#) ou Protected et Overridable (en Visual Basic). Nommez cette méthode OnEventName ; par exemple, OnDataReceived. La méthode doit prendre un paramètre qui spécifie un objet de données d'événement, qui est un objet de type EventArgs ou un type dérivé. Vous fournissez cette méthode pour permettre aux classes dérivées de substituer la logique de déclenchement d'événement. Une classe dérivée doit toujours appeler la méthode OnEventName de la classe de base pour garantir que les délégués inscrits reçoivent l’événement.

L'exemple suivant montre comment déclarer un évènement appelé ThresholdReached. L'événement est associé au délégué EventHandler et déclenché dans une méthode nommée OnThresholdReached.

class Counter
{
    public event EventHandler ThresholdReached;

    protected virtual void OnThresholdReached(EventArgs e)
    {
        EventHandler handler = ThresholdReached;
        handler?.Invoke(this, e);
    }

    // provide remaining implementation for the class
}
Public Class Counter
    Public Event ThresholdReached As EventHandler

    Protected Overridable Sub OnThresholdReached(e As EventArgs)
        RaiseEvent ThresholdReached(Me, e)
    End Sub

    ' provide remaining implementation for the class
End Class

Délégués

Un délégué est un type qui détient une référence à une méthode. Un délégué est déclaré avec une signature qui indique le type de retour et les paramètres des méthodes qu'il référence, et il peut contenir des références à des méthodes qui correspondent à sa signature. Un délégué est donc équivalent à un rappel ou un pointeur de fonction de type sécurisé. Une déclaration Delegate suffit à définir une classe déléguée.

Les délégués ont de nombreux usages dans .NET. Dans le contexte des événements, un délégué est un intermédiaire (ou un mécanisme similaire aux pointeurs) entre la source d'événements et le code qui gère l'événement. Vous associez un délégué à un événement en incluant le type de délégué dans la déclaration de l'événement, comme indiqué dans l'exemple de la section précédente. Pour plus d'informations sur les délégués, consultez la classe Delegate.

.NET fournit les délégués EventHandler et EventHandler<TEventArgs> pour prendre en charge la plupart des scénarios d'événement. Utilisez le délégué EventHandler pour tous les événements qui n'incluent pas de données d'événement. Utilisez le délégué EventHandler<TEventArgs> pour les événements qui incluent des données sur l'événement. Ces délégués n’ont aucune valeur de type de retour et prennent deux paramètres (un objet pour la source de l’événement et un objet pour les données d’événement).

Les délégués sont multidiffusion, ce qui signifie qu'ils peuvent contenir des références à plusieurs méthodes de gestion des événements. Pour plus d'informations, consultez la page de référence Delegate. Les délégués assurent une souplesse et un contrôle précis lors de la gestion des événements. Un délégué agit comme un répartiteur d’événements pour la classe qui déclenche l’événement en gérant une liste de gestionnaires d’événements inscrits pour l’événement.

Pour les scénarios dans lesquels les délégués EventHandler et EventHandler<TEventArgs> ne fonctionnent pas, vous pouvez définir un délégué. Les scénarios qui nécessitent de définir un délégué sont très rares, par exemple lorsque vous devez utiliser du code qui ne reconnaît pas les génériques. Vous marquez un délégué avec le mot clé C# delegateet Visual Basic Delegate dans la déclaration. L'exemple suivant montre comment déclarer un délégué nommé ThresholdReachedEventHandler.

public delegate void ThresholdReachedEventHandler(object sender, ThresholdReachedEventArgs e);
Public Delegate Sub ThresholdReachedEventHandler(sender As Object, e As ThresholdReachedEventArgs)

Données d’événement

Les données associées à un événement peuvent être obtenues via une classe de données d'événement. .NET fournit plusieurs classes de données d'événement que vous pouvez utiliser dans vos applications. Par exemple, la classe SerialDataReceivedEventArgs est la classe de données d'événement pour l'événement SerialPort.DataReceived. .NET suit un modèle d'affectation de nom qui veut que toutes les classes de données d'évènement se terminent par EventArgs. Pour savoir quelle classe de données d'événement est associée à un événement, il suffit d'examiner le délégué de l'événement. Par exemple, le délégué SerialDataReceivedEventHandler inclut la classe SerialDataReceivedEventArgs comme paramètre.

La classe EventArgs est le type de base pour toutes les classes de données d'événement. EventArgs est également la classe que vous utilisez quand un événement n'a pas de données associée. Lorsque vous créez un événement qui vise uniquement à notifier à d'autres classes que quelque chose est survenu et n'a pas besoin de passer des données, incluez la classe EventArgs comme deuxième paramètre du délégué. Vous pouvez passer la valeur EventArgs.Empty lorsqu'aucune donnée n'est fournie. Le délégué EventHandler inclut la classe EventArgs comme paramètre.

Lorsque vous souhaitez créer une classe personnalisée de données d'événement, créez une classe qui dérive de EventArgs, puis fournissez tous les membres requis pour passer les données liées à l'événement. En général, vous devriez utiliser le même modèle d'affectation de noms que .NET et terminer le nom de classe de données d'événement par EventArgs.

L'exemple suivant illustre une classe de données d'événement nommée ThresholdReachedEventArgs. Elle contient les propriétés spécifiques à l'événement déclenché.

public class ThresholdReachedEventArgs : EventArgs
{
    public int Threshold { get; set; }
    public DateTime TimeReached { get; set; }
}
Public Class ThresholdReachedEventArgs
    Inherits EventArgs

    Public Property Threshold As Integer
    Public Property TimeReached As DateTime
End Class

Gestionnaires d’événements

Pour répondre à un événement, vous définissez une méthode de gestion d'événements dans le récepteur d'événements. Cette méthode doit correspondre à la signature du délégué pour l'événement géré. Dans le gestionnaire des évènements, vous exécutez les actions nécessaires lorsque l'événement est déclenché, comme la collecte de l'entrée d'utilisateur après que l'utilisateur clique sur un bouton. Pour recevoir des notifications lorsque l'événement se produit, la méthode de votre gestionnaire d'événements doit s'abonner à l'événement.

L'exemple suivant présente une méthode de gestionnaire d'événements nommée c_ThresholdReached qui correspond à la signature du délégué EventHandler. La méthode s'abonne à l'événement ThresholdReached.

class Program
{
    static void Main()
    {
        var c = new Counter();
        c.ThresholdReached += c_ThresholdReached;

        // provide remaining implementation for the class
    }

    static void c_ThresholdReached(object sender, EventArgs e)
    {
        Console.WriteLine("The threshold was reached.");
    }
}
Module Module1

    Sub Main()
        Dim c As New Counter()
        AddHandler c.ThresholdReached, AddressOf c_ThresholdReached

        ' provide remaining implementation for the class
    End Sub

    Sub c_ThresholdReached(sender As Object, e As EventArgs)
        Console.WriteLine("The threshold was reached.")
    End Sub
End Module

Gestionnaires d’événements statiques et dynamiques

.NET permet aux abonnés de s’inscrire pour les notifications d’événements statiques ou dynamiques. Les gestionnaires d’événements statiques sont en vigueur pendant toute la durée de vie de la classe dont ils gèrent les événements. Les gestionnaires d’événements dynamiques sont explicitement activés et désactivés pendant l’exécution du programme, généralement en réponse à une logique de programme conditionnelle. Par exemple, ils peuvent être utilisés si les notifications d’événements sont nécessaires uniquement dans certaines conditions ou si une application fournit plusieurs gestionnaires d’événements et les conditions d’exécution définissent le gestionnaire approprié à utiliser. L'exemple de la section précédente indique comment ajouter dynamiquement un gestionnaire d'événements. Pour plus d’informations, consultez Événements (en Visual Basic) et Événements (en C#).

Déclenchement de plusieurs événements

Si votre classe déclenche plusieurs événements, le compilateur génère un champ par instance de délégué d'événement. Si le nombre d’événements est important, le coût de stockage d’un champ par délégué peut ne pas convenir. Dans ce cas, .NET fournit les propriétés de l’événement que vous pouvez utiliser avec une autre structure de données de votre choix pour stocker les délégués d’événements.

Les propriétés de l’événement se composent de déclarations d’événement accompagnées d’accesseurs d’événement. Les accesseurs d'événement sont des méthodes que vous définissez pour que des instances de délégué d'événement puissent être ajoutées ou supprimées de la structure des données de stockage. Notez que les propriétés d'événement sont plus lentes que les champs d'événement, car chaque délégué d'événement doit être récupéré avant de pouvoir être appelé. Le compromis réside entre la mémoire et la vitesse. Si votre classe définit de nombreux événements qui sont déclenchés peu fréquemment, vous souhaiterez implémenter les propriétés de l’événement. Pour plus d’informations, consultez Comment : gérer plusieurs événements à l’aide des propriétés d’événements.

Titre Description
Comment : déclencher et utiliser des événements Contient des exemples de déclenchement et de consommation d'événements.
Comment : gérer plusieurs événements à l'aide des propriétés d'événements Montre comment utiliser des propriétés d'événement pour gérer plusieurs événements.
Modèle de conception d’observateur Décrit le modèle de conception qui permet à un abonné de s’inscrire pour recevoir des notifications d’un fournisseur.

Voir aussi