354 votes

Comprendre les événements et les gestionnaires d'événements en C #

Je comprends le but des événements, en particulier dans le contexte de la création d'interfaces utilisateur. Je pense que c'est le prototype pour créer un événement:

 public void EventName(object sender, EventArgs e);
 

Que font les gestionnaires d'événements, pourquoi sont-ils nécessaires et comment en créer un?

697voto

Rex M Points 80372

Pour comprendre les gestionnaires d'événements, vous devez comprendre les délégués. En C#, vous pouvez penser à un délégué comme un pointeur (ou une référence) à une méthode. Ceci est utile parce que le pointeur peut être adopté comme une valeur.

Le concept central d'un délégué est sa signature, ou de la forme. C'est le type de retour et les paramètres d'entrée. Par exemple, si nous créons un délégué void MyDelegate(object sender, EventArgs e),, il ne peut point des méthodes qui retournent void, et de prendre une object et EventArgs. Un peu comme un trou carré et une cheville carrée. Donc nous disons que ces méthodes ont la même signature, ou de la forme, en tant que délégué.

Afin de savoir comment créer une référence à une méthode, nous allons réfléchir à la finalité des événements: nous voulons provoquer un peu de code à exécuter lorsque quelque chose se passe ailleurs dans le système - ou "gérer l'événement". Pour ce faire, nous créons des méthodes spécifiques pour le code que nous voulons être exécuté. La colle entre les événements et les méthodes à exécuter sont les délégués. L'événement doit en interne stocker une "liste" de pointeurs vers les méthodes à appeler lorsque l'événement est déclenché.* Bien sûr, nous avons besoin de savoir quels sont les arguments à passer à une méthode pour être en mesure à l'appeler - nous utilisons le délégué, le "contrat" entre l'événement et de toutes les méthodes spécifiques.

Donc la valeur par défaut EventHandler (et beaucoup d'autres) représente une forme spécifique de la méthode (encore une fois, nulle/objet-EventArgs). Lorsque vous déclarez un événement, vous dites ce qui forme de la méthode (Gestionnaire) que l'événement va invoquer, en spécifiant un délégué:

//This delegate can be used to point to methods
//which return void and take a string.
public delegate void MyEventHandler(string foo);

//This event can cause any method which conforms
//to MyEventHandler to be called.
public event MyEventHandler SomethingHappened;

//Here is some code I want to be executed
//when SomethingHappened fires.
void HandleSomethingHappened(string foo)
{
    //Do some stuff
}

//I am creating a delegate (pointer) to HandleSomethingHappened
//and adding it to SomethingHappened's list of "Event Handlers".
myObj.SomethingHappened += new MyEventHandler(HandleSomethingHappened);

(*C'est la clé des événements .NET et des peelings à l'écart de la "magie" - un événement est vraiment, sous les couvertures, juste une liste des méthodes de la même "forme". La liste est stockée dans lequel l'événement de vie. Lorsque l'événement est "élevé", c'est vraiment juste "passer à travers cette liste de méthodes et d'appeler chacun, à l'aide de ces valeurs que les paramètres". Affectation d'un gestionnaire d'événements est juste une plus belle, la plus facile d'ajouter votre méthode pour cette liste de méthodes pour être appelé).

110voto

taoufik Points 2784

C# connaît deux mandats, delegate et event. Commençons avec la première.

Délégué

Un delegate est une référence à une méthode. Comme vous pouvez créer une référence à une instance:

MyClass instance = myFactory.GetInstance();

Vous pouvez utiliser un délégué pour créer une référence à une méthode:

Action myMethod = myFactory.GetInstance;

Maintenant que vous avez cette référence à une méthode, vous pouvez appeler la méthode par la référence:

MyClass instance = myMethod();

Mais pourquoi le feriez-vous? Vous pouvez aussi appeler myFactory.GetInstance() directement. Dans ce cas, vous pouvez. Cependant, il existe de nombreux cas pour réfléchir à l'endroit où vous ne voulez pas le reste de l'application des connaissances de l' myFactory ou à l'appel d' myFactory.GetInstance() directement.

Évidente est que si vous voulez être en mesure de remplacer myFactory.GetInstance() en myOfflineFakeFactory.GetInstance() d'une place centrale (aka usine méthode de motif).

Méthode de fabrique de modèle

Donc, si vous avez un TheOtherClass de la classe et qu'il doit utiliser l' myFactory.GetInstance(), c'est la façon dont le code ressemblera sans délégués (vous aurez besoin de laissez - TheOtherClass connaître le type de votre myFactory):

TheOtherClass toc;
//...
toc.SetFactory(myFactory);


class TheOtherClass
{
   public void SetFactory(MyFactory factory)
   {
      // set here
   }

}

Si vous souhaitez utiliser les délégués, vous n'avez pas à exposer le type de mon usine:

TheOtherClass toc;
//...
Action factoryMethod = myFactory.GetInstance;
toc.SetFactoryMethod(factoryMethod);


class TheOtherClass
{
   public void SetFactoryMethod(Action factoryMethod)
   {
      // set here
   }

}

Ainsi, vous pouvez donner un délégué de classe à utiliser, sans exposer votre type. La seule chose que vous exposez est la signature de votre méthode (le nombre de paramètres que vous avez et tel).

"La Signature de ma méthode", où ai-je entendu cela avant? O oui, interfaces!!! les interfaces de décrire la signature de l'ensemble de la classe. Pensez délégués décrivant la signature d'une seule méthode!

Une autre grande différence entre une interface et d'un délégué, c'est que lorsque vous avez écrit votre classe, vous n'avez pas à dire à C# "cette méthode met en œuvre ce type de déléguer". Avec les interfaces que vous avez besoin de dire "cette classe met en œuvre ce type d'interface".

En outre, un délégué de référence (avec quelques restrictions, voir ci-dessous) référence à plusieurs méthodes (appelées MulticastDelegate). Cela signifie que lorsque vous appelez le délégué, plusieurs explicitement-joint méthodes seront exécutées. Une référence de l'objet peut toujours seule référence à un objet.

Les restrictions pour un MulticastDelegate sont de la méthode ou de son délégué) signature ne doit pas avoir une valeur de retour (void) et les mots-clés out et ref ne sont pas utilisés dans la signature. Évidemment, vous ne pouvez pas appeler deux méthodes qui retournent un nombre, et attendre d'eux de revenir par le même nombre. Une fois que la signature est conforme, le délégué est automatiquement MulticastDelegate.

L'événement

Les événements sont seulement des propriétés (comme le get;set; propriétés des champs d'instance) qui exposent abonnement à la déléguer à partir d'autres objets. Ces propriétés, mais ne pas appuyer " get;set;. Au lieu de cela ils soutiennent ajouter;supprimer;

De sorte que vous pouvez avoir:

    Action myField;

    public event Action MyProperty
    {
        add { myField += value; }
        remove { myField -= value; }
    }

L'utilisation de l'INTERFACE utilisateur (WinForms)

Donc, maintenant nous savons qu'un délégué est une référence à une méthode et que l'on peut avoir d'un événement à faire savoir au monde qu'ils peuvent nous donner leurs méthodes pour être référencé à partir de notre délégué, et nous sommes un bouton de l'INTERFACE utilisateur, puis: on peut demander à n'importe qui qui est intéressé à savoir si j'ai été cliqué, pour enregistrer leur méthode avec nous (par l'intermédiaire de l'événement, nous avons exposé). Il peut utiliser toutes les méthodes qui nous ont été donnés, et de les référencer par notre délégué. Et puis, nous allons attendre et attendre.... jusqu'à ce qu'un utilisateur vient et clique sur le bouton, puis nous allons avoir assez de raison d'invoquer le délégué. Et parce que le délégué références de toutes ces méthodes, toutes ces méthodes sera invoquée. Nous ne savons pas ce que ces méthodes font, ni nous savons que la classe implémente ceux de la méthode. Tous nous ne de soins, c'est que quelqu'un était intéressé à nous d'être cliqué, et nous a donné une référence à une méthode qui respecte nos souhaité signature.

Java

Des langues comme Java n'ont pas de délégués. Ils utilisent des interfaces à la place. La façon de faire c'est de demander à quelqu'un qui est intéressé par "nous, cliqué sur", pour mettre en œuvre un certain interface (avec une certaine méthode, nous pouvons l'appeler), puis nous donner la totalité de l'instance qui implémente l'interface. Nous pouvons que garder une liste de tous les objets implémentant cette interface, et de peuvent appeler leur "certaines méthode, nous pouvons appeler" dès qu'on a cliqué.

43voto

Gary Willoughby Points 13366

Voici un exemple de code qui peut aider

 using System;
using System.Collections.Generic;
using System.Text;

namespace Event_Example
{
  // First we have to define a delegate that acts as a signature for the
  // function that is ultimately called when the event is triggered.
  // You will notice that the second parameter is of MyEventArgs type.
  // This object will contain information about the triggered event.

  public delegate void MyEventHandler(object source, MyEventArgs e);

  // This is a class which describes the event to the class that recieves it.
  // An EventArgs class must always derive from System.EventArgs.

  public class MyEventArgs : EventArgs
  {
    private string EventInfo;

    public MyEventArgs(string Text) {
      EventInfo = Text;
    }

    public string GetInfo() {
      return EventInfo;
    }
  }

  // This next class is the one which contains an event and triggers it
  // once an action is performed. For example, lets trigger this event
  // once a variable is incremented over a particular value. Notice the
  // event uses the MyEventHandler delegate to create a signature
  // for the called function.

  public class MyClass
  {
    public event MyEventHandler OnMaximum;

    private int i;
    private int Maximum = 10;

    public int MyValue
    {
      get { return i; }
      set
      {
        if(value <= Maximum) {
          i = value;
        }
        else {
          // To make sure we only trigger the event if a handler is present
          // we check the event to make sure it's not null.
          if(OnMaximum != null) {
            OnMaximum(this, new MyEventArgs("You've entered " +
              value.ToString() +
              ", but the maximum is " +
              Maximum.ToString()));
          }
        }
      }
    }
  }

  class Program
  {
    //This is the actual method that will be assigned to the event handler
    //within the above class. This is where we perform an action once the
    //event has been triggered.

    static void MaximumReached(object source, MyEventArgs e) {
      Console.WriteLine(e.GetInfo());
    }

    static void Main(string[] args) {
      //Now lets test the event contained in the above class.
      MyClass MyObject = new MyClass();
      MyObject.OnMaximum += new MyEventHandler(MaximumReached);
      for(int x = 0; x <= 15; x++) {
        MyObject.MyValue = x;
      }
      Console.ReadLine();
    }
  }
}
 

43voto

Andy Points 15910

C'est en fait la déclaration pour un gestionnaire d'événement - une méthode qui sera appelée lorsqu'un événement est déclenché. Pour créer un événement, vous devez écrire quelque chose comme ceci:

public class Foo
{
    public event EventHandler MyEvent;
}

Et puis vous pouvez vous inscrire à l'événement comme ceci:

Foo foo = new Foo();
foo.MyEvent += new EventHandler(this.OnMyEvent);

Avec OnMyEvent() définie comme ceci:

private void OnMyEvent(object sender, EventArgs e)
{
    MessageBox.Show("MyEvent fired!");
}

Chaque fois qu' Foo déclenche MyEvent, alors votre OnMyEvent gestionnaire sera appelé.

Vous n'avez pas toujours à utiliser une instance de EventArgs comme second paramètre. Si vous souhaitez inclure des informations supplémentaires, vous pouvez utiliser une classe dérivée de EventArgs (EventArgs est la base d'une convention). Par exemple, si vous regardez certains des événements définis sur Control en WinForms, ou FrameworkElement en WPF, vous pouvez voir des exemples d'événements qui passent de l'information supplémentaire pour les gestionnaires d'événements.

19voto

Gulzar Nazim Points 35342

Délégués .NET: AC # Bedtime Story est un ancien article utile que j'ai trouvé sur les délégués et les événements. C'est pour C # 2.0.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X