Événements

Références

L'actualité

Librairie

L'information

Introduction

Les événements permettent à une classe ou à un objet de notifier d'autres classes ou objets quand quelque chose de significatif se produit. La classe qui envoie (ou déclenche) l'événement est appelée publieur et les classes qui reçoivent (ou gèrent) l'événement sont appelées abonnés.

Dans une application C# Windows Forms ou web classique, vous vous abonnez à des événements déclenchés par des contrôles, comme des boutons et des zones de liste. Vous pouvez utiliser l'IDE Visual C# pour parcourir les événements publiés par un contrôle et sélectionner ceux que vous voulez gérer. L'IDE permet d'ajouter automatiquement une méthode de gestionnaire d'événements vide et le code pour vous abonner à l'événement.

Vue d'ensemble des événements

Les événements ont les propriétés suivantes :

  • Le publieur détermine quand un événement est déclenché ; les abonnés déterminent l'action entreprise en réponse à l'événement.
  • Un événement peut avoir plusieurs abonnés. Un abonné peut gérer plusieurs événements provenant de plusieurs publieurs.
  • Les événements qui n'ont aucun abonné ne sont jamais déclenchés.
  • Les événements sont généralement utilisés pour signaler des actions de l'utilisateur, comme les clics de bouton ou les sélections de menu dans les interfaces utilisateur graphiques.
  • Quand un événement a plusieurs abonnés, les gestionnaires d'événements sont appelées de façon synchrone quand un événement est déclenché. Pour appeler des événements de façon asynchrone, consultez "appel de méthodes synchrones de façon asynchrone".
  • Dans la bibliothèque de classes .NET Framework , les événements sont basés sur le délégué EventHandler et la classe de base EventArgs.

Abonnement à des événements

Vous vous abonnez à un événement publié par une autre classe lorsque vous voulez écrire du code personnalisé qui doit être appelé quand cet événement est déclenché. Par exemple, vous pouvez vous abonner à l'événement click d'un bouton pour permettre à votre application de réagir lorsque l'utilisateur clique sur le bouton.

Pour s'abonner aux événements à l'aide de l'IDE de Visual Studio

Si vous ne voyez pas la fenêtre Propriétés, en mode Création, cliquez sur le formulaire ou le contrôle pour lequel vous voulez créer un gestionnaire d'événements, puis sélectionnez Propriétés. En haut de la fenêtre Propriétés, cliquez sur l'icône événements. Double-cliquez sur l'événement que vous voulez créer, par exemple l'événement Load.

Visual C# crée une méthode de gestionnaire d'événements vide et l'ajoute à votre code. Vous pouvez également ajouter le code manuellement en mode Code. Par exemple, les lignes de code suivantes déclarent une méthode de gestionnaire d'événements qui est appelée lorsque la classe Form déclenche l'événement Load.

La ligne de code qui est nécessaire pour s'abonner à l'événement est aussi générée automatiquement dans la méthode InitializeComponent, dans le fichier Form1.Designer.cs de votre projet. Elle ressemble à ceci :

Pour s'abonner aux événements par programmation

Définissez une méthode de gestionnaire d'événements dont la signature correspond à la signature du délégué de l'événement. Par exemple, si l'événement est basé sur le type délégué EventHandler, le code suivant représente le stub de méthode :

Utilisez l'opérateur d'assignation d'addition (+=) pour attacher votre gestionnaire d'événements à l'événement. Dans l'exemple suivant, nous allons supposer qu'un objet nommé publisher a un événement nommé RaiseCustomEvent. Notez que la classe d'abonné nécessite une référence à la classe d'éditeur pour s'abonner à ses événements.

Notez que la syntaxe précédente est une nouveauté du langage C# 2.0. Elle équivaut exactement à la syntaxe du C# 1.0, dans laquelle le délégué d'encapsulation doit être explicitement créé à l'aide du mot clé new :

Vous pouvez également ajouter un gestionnaire d'événements à l'aide d'une expression lambda :

Pour s'abonner aux événements à l'aide d'une méthode anonyme

Si vous savez que vous n'aurez pas à vous désabonner d'un événement, vous pouvez utiliser l'opérateur d'assignation d'addition (+=) pour attacher une méthode anonyme à l'événement. Dans l'exemple suivant, nous supposons qu'un objet nommé publisher a un événement nommé RaiseCustomEvent, et qu'une classe CustomEventArgs a également été définie pour contenir des informations d'événements spécialisés. Notez que la classe d'abonné nécessite une référence à publisher pour s'abonner à ses événements.

Il est important de noter que vous ne pourrez pas vous désabonner facilement d'un événement si vous avez utilisé une fonction anonyme pour vous y inscrire. Pour vous désinscrire dans ce scénario, accédez au code dans lequel vous vous êtes abonné à l'événement, stockez la méthode anonyme dans une variable de délégué, puis ajoutez le délégué à l'événement. En général, nous recommandons de ne pas utiliser de fonctions anonymes pour vous abonner aux événements si vous devez vous en désabonner plus tard dans votre code. Pour plus d'informations sur les fonctions anonymes, consultez Fonctions anonymes.

Désabonnement

Pour éviter que votre gestionnaire d'événements ne soit appelé lorsque l'événement est déclenché, désabonnez-vous de l'événement. Pour empêcher les fuites de ressources, vous devez vous désabonner des événements avant d'éliminer un objet d'abonné. Tant que vous êtes abonné à un événement, le délégué de multidiffusion qui se trouve sous l'événement, dans l'objet de publication, comporte une référence au délégué qui encapsule le gestionnaire d'événements de l'abonné. Tant que l'objet de publication contient cette référence, le garbage collection ne supprime pas l'objet d'abonné.

Pour se désabonner d'un événement

Utilisez l'opérateur d'assignation de soustraction (-=) pour vous désabonner d'un événement :

Lorsque tous les abonnés se sont désabonnés d'un événement, l'instance d'événement de la classe d'éditeur est définie sur null.

Publier des événements

La procédure suivante montre comment ajouter à vos classes et structures des événements qui respectent le modèle .NET Framework standard. Tous les événements de la bibliothèque de classes .NET Framework sont basés sur le délégué EventHandler, qui est défini comme suit :

Le .NET Framework 2.0 introduit une version générique de ce délégué : EventHandler‹TEventArgs›. Les exemples suivants montrent comment utiliser les deux versions.

Bien que les événements des classes que vous définissez puissent être basés sur n'importe quel type délégué valide, même les délégués qui retournent une valeur, il est généralement recommandé de baser les événements sur le modèle .NET Framework à l'aide de EventHandler, comme dans l'exemple suivant.

Pour publier des événements basés sur le modèle EventHandler

(Ignorez cette étape si vous n'avez pas à envoyer de données personnalisées avec votre événement). Déclarez la classe pour vos données personnalisées avec une étendue visible par vos classes de serveur de publication et d'abonné. Ajoutez ensuite les membres nécessaires pour contenir vos données d'événement personnalisées. Dans cet exemple, une simple chaîne est retournée.

(Ignorez cette étape si vous utilisez la version générique de EventHandler‹TEventArgs›). Déclarez un délégué dans votre classe de publication. Donnez-lui un nom qui se termine par EventHandler. Le deuxième paramètre spécifie votre type EventArgs personnalisé.

Déclarez l'événement dans votre classe de publication en effectuant l'une des étapes suivantes.

Si vous n'avez aucune classe EventArgs personnalisée, votre type d'événement sera le délégué EventHandler non générique. Il est inutile de déclarer le délégué, car il l'est déjà dans l'espace de noms System inclus au moment où vous créez votre projet C#. Ajoutez le code suivant à votre classe de serveur de publication.

Si vous utilisez la version non générique de EventHandler et que vous avez une classe personnalisée dérivée de EventArgs, déclarez votre événement à l'intérieur de votre classe de publication et utilisez votre délégué de l'étape 2 comme type.

Si vous utilisez la version générique, vous n'avez pas besoin de délégué personnalisé. Au lieu de cela, dans votre classe de publication, vous spécifiez votre type d'événement en tant que EventHandler‹CustomEventArgs›, en insérant le nom de votre propre classe entre les crochets.

Exemple

L'exemple suivant est une illustration des étapes précédentes avec l'utilisation d'une classe EventArgs personnalisée et de EventHandler‹TEventArgs› comme type d'événement.


Déclencher les événements

L'exemple suivant montre la méthode standard employée pour déclarer des événements dans une classe de base pour qu'ils puissent être déclenchés à partir de classes dérivées. Ce modèle est largement utilisé dans les classes Windows Forms de la bibliothèque de classes .NET Framework.

Lorsque vous créez une classe qui peut être utilisée comme classe de base pour d'autres classes, tenez compte du fait que les événements constituent un type spécial de délégué qui ne peut être appelé qu'à partir de la classe qui les a déclarés. Les classes dérivées ne peuvent pas appeler directement les événements qui sont déclarés dans la classe de base. Même si vous pouvez avoir besoin d'un événement qui ne peut être déclenché que par la classe de base, la plupart du temps, vous devez permettre à la classe dérivée d'appeler les événements de la classe de base. Pour ce faire, vous pouvez créer une méthode d'appel protégée dans la classe de base qui encapsule l'événement. En appelant ou en substituant cette méthode d'appel, les classes dérivées peuvent appeler indirectement l'événement.

Ne déclarez pas les événements virtuels dans une classe de base et substituez-les dans une classe dérivée. Le compilateur C# ne gère pas correctement ce type d'événement et il n'est pas possible de prévoir si un abonné de l'événement dérivé s'abonnera à l'événement de classe de base.

Exemple



Implémenter des événements d'interface

Une interface peut déclarer un événement. L'exemple suivant montre comment implémenter des événements d'interface dans une classe. En gros, les règles sont les mêmes que quand vous implémentez une propriété ou une méthode d'interface.

Pour implémenter des événements d'interface dans une classe

Déclarez l'événement dans votre classe, puis appelez-le aux emplacements appropriés.

Exemple

L'exemple suivant montre comment gérer la situation peu courante dans laquelle votre classe hérite de plusieurs interfaces et chaque interface a un événement ayant le même nom. Dans ce cas, vous devez fournir une implémentation d'interface explicite pour au moins l'un des événements. Quand vous écrivez une implémentation d'interface explicite pour un événement, vous devez également écrire les accesseurs d'événement add et remove. Normalement, ces éléments sont fournis par le compilateur, mais dans le cas en question le compilateur ne peut pas les fournir.

En fournissant vos propres accesseurs, vous pouvez spécifier si les deux événements sont représentés par le même événement dans votre classe ou par des événements différents. Par exemple, si les événements doivent être déclenchés à des moments différents en fonction des spécifications de l'interface, vous pouvez associer chaque événement à une implémentation distincte dans votre classe. Dans l'exemple suivant, les abonnés déterminent l'événement OnDraw qu'il recevront en effectuant un cast de la référence de la forme en IShape ou IDrawingObject.


Utiliser un dictionnaire avec des événements

Une des façons d'utiliser accessor-declarations consiste à exposer un grand nombre d'événements sans allouer de champ à chaque événement, mais en utilisant à la place un dictionnaire pour stocker les instances d'événements. Cette méthode n'est utile qu'en présence d'un grand nombre d'événements dont la plupart ne seront pas implémentés.


Implémenter des accesseurs d'événement personnalisés

Un événement constitue un genre spécial de délégué multicast qui peut être appelé uniquement à partir de la classe dans laquelle il est déclaré. Le code client s'abonne à l'événement en fournissant une référence à une méthode qui doit être appelée quand l'événement est déclenché. Ces méthodes sont ajoutées à la liste d'invocation du délégué par le biais des accesseurs d'événement, qui ressemblent aux accesseurs de propriété, sauf que les accesseurs d'événement sont nommés add et remove. Dans la plupart des cas, vous n'avez pas à fournir d'accesseurs d'événement personnalisés. Quand aucun accesseur d'événement personnalisé n'est fourni dans votre code, le compilateur les ajoute automatiquement. Toutefois, vous devez parfois fournir un comportement personnalisé. Ce genre de cas est illustré dans la rubrique Guide pratique pour implémenter des événements d'interface.

Exemple

L'exemple suivant indique comment implémenter des accesseurs d'événement add et remove. Même si vous pouvez remplacer le code à l'intérieur des accesseurs, nous vous recommandons de verrouiller l'événement avant d'ajouter ou de supprimer une nouvelle méthode de gestionnaire d'événements.