web-dev-qa-db-fra.com

événement personnalisé simple

J'essaie d'apprendre des événements personnalisés et j'ai essayé d'en créer un, mais il semble que j'ai un problème.

J'ai créé un formulaire, une classe statique et un événement personnalisé. Ce que j'essaie de faire, c'est d'appuyer sur le bouton Form pour appeler la fonction de classe statique, puis func déclenche de temps en temps un événement pour signaler l'état actuel. Form1 écoutera si l'événement est levé et si c'est le cas, il changera Texte de label1

Voici ce que j'ai jusqu'ici

public partial class Form1 : Form
{
    public EventHandler<Progress> progress; 

    public Form1()
    {
        InitializeComponent();
        progress += SetStatus;
    }

    private void SetStatus(object sender, Progress e)
    {
        label1.Text = e.Status;
    }

    private void button1_Click_1(object sender, EventArgs e)
    {
         TestClass.Func();
    }

 }

Fichier 2

class TestClass
{
    public static void Func()
    {
        //time consuming code
        Report status 
        // time consuming code
        report status
    }
}

public class Progress : EventArgs
{
    public string Status { get; private set; }

    private Progress() {}

    public Progress(string status)
    {
        Status = status;
    }
}

Maintenant, ce que je ne comprends pas, c'est comment puis-je générer un événement à partir de TestClass afin que Form1 puisse gérer l'événement et modifier label.Text

71
Bill

C'est un moyen facile de créer des événements personnalisés et de les générer. Vous créez un délégué et un événement dans la classe à partir de laquelle vous lancez. Ensuite, abonnez-vous à l'événement à partir d'une autre partie de votre code. Vous avez déjà une classe d'argument d'événement personnalisé, vous pouvez donc l'utiliser pour créer d'autres classes d'argument d'événement. N.B: Je n'ai pas compilé ce code.

public partial class Form1 : Form
{
    private TestClass _testClass;
    public Form1()
    {
        InitializeComponent();
        _testClass = new TestClass();
        _testClass.OnUpdateStatus += new TestClass.StatusUpdateHandler(UpdateStatus);
    }

    private void UpdateStatus(object sender, ProgressEventArgs e)
    {
        SetStatus(e.Status);
    }

    private void SetStatus(string status)
    {
        label1.Text = status;
    }

    private void button1_Click_1(object sender, EventArgs e)
    {
         TestClass.Func();
    }

}

public class TestClass
{
    public delegate void StatusUpdateHandler(object sender, ProgressEventArgs e);
    public event StatusUpdateHandler OnUpdateStatus;

    public static void Func()
    {
        //time consuming code
        UpdateStatus(status);
        // time consuming code
        UpdateStatus(status);
    }

    private void UpdateStatus(string status)
    {
        // Make sure someone is listening to event
        if (OnUpdateStatus == null) return;

        ProgressEventArgs args = new ProgressEventArgs(status);
        OnUpdateStatus(this, args);
    }
}

public class ProgressEventArgs : EventArgs
{
    public string Status { get; private set; }

    public ProgressEventArgs(string status)
    {
        Status = status;
    }
}
131
themartinmcfly

Vous n'avez pas créé d'événement. Pour faire cela écris:

public event EventHandler<Progress> Progress;

Ensuite, vous pouvez appeler Progress depuis la classe où elle a été déclarée comme une fonction normale ou un délégué:

Progress(this, new Progress("some status"));

Donc, si vous voulez signaler la progression dans TestClass, l'événement doit également y figurer et il doit également être statique. Vous pouvez le souscrire à partir de votre formulaire comme ceci:

TestClass.Progress += SetStatus;

En outre, vous devriez probablement renommer Progress en ProgressEventArgs, afin que le nom soit clair.

19
svick

Les événements sont assez faciles en C #, mais les documents MSDN, à mon avis, les rendent assez déroutants. Normalement, la plupart des documents que vous voyez traitent de la création d’une classe héritée de la classe de base EventArgs et il y a ne raison pour ça. Cependant, ce n'est pas le moyen le plus simple de créer des événements, et pour quelqu'un qui veut quelque chose de rapide, facile et rapide, utiliser le type Action constitue votre ticket.

Créer des événements et s'y abonner

1. Créez votre événement sur votre classe juste après votre déclaration class.

public event Action<string,string,string,string>MyEvent;

2. Créez votre méthode de classe de gestionnaire d'événements dans votre classe.

private void MyEventHandler(string s1,string s2,string s3,string s4)
{
  Console.WriteLine("{0} {1} {2} {3}",s1,s2,s3,s4);
}

3. Maintenant, lorsque votre classe est appelée, dites-lui de connecter l'événement à votre nouveau gestionnaire d'événements. La raison pour laquelle le += opérateur est utilisé parce que vous ajoutez votre gestionnaire d’événements particulier à l’événement. Pour ce faire, vous pouvez utiliser plusieurs gestionnaires d'événements distincts. Lorsqu'un événement est déclenché, chaque gestionnaire d'événement fonctionne dans l'ordre dans lequel vous les avez ajoutés.

class Example
{
  public Example() // I'm a C# style class constructor
  {
    MyEvent += new Action<string,string,string,string>(MyEventHandler);
  }
}

4. Maintenant, quand vous êtes prêt, déclenchez (c'est-à-dire soulevez) l'événement quelque part dans votre code de classe comme ceci:

MyEvent("wow","this","is","cool");

Le résultat final lorsque vous exécutez ceci est que la console émettra "wow c'est cool". Et si vous changiez "cool" avec une date ou une séquence et si vous exécutiez ce déclencheur d'événement plusieurs fois, vous verriez le résultat apparaître dans une séquence FIFO comme si les événements devaient normalement fonctionner.

Dans cet exemple, j'ai passé 4 chaînes. Mais vous pouvez changer ceux-ci en n'importe quel type de type acceptable, ou utiliser plus ou moins de types, ou même supprimer le <...> et ne transmettez rien à votre gestionnaire d’événements.

Et, encore une fois, si vous aviez plusieurs gestionnaires d’événements personnalisés et que vous les avez tous abonnés à votre événement avec le += _ opérateur, votre déclencheur d’événement les aurait appelés tous en séquence.

Identifier les appelants à l'événement

Mais que faire si vous voulez identifier l'appelant de cet événement dans votre gestionnaire d'événements? Ceci est utile si vous voulez un gestionnaire d'événements qui réagit avec des conditions en fonction de la personne qui a déclenché/déclenché l'événement. Il y a quelques façons de le faire. Vous trouverez ci-dessous des exemples illustrés par leur rapidité:

Option 1. (Le plus rapide) Si vous le connaissez déjà, transmettez le nom sous forme de chaîne littérale au gestionnaire d'événements lorsque vous le déclenchez.

Option 2. (Assez rapide) Ajoutez ceci à votre classe et appelez-le à partir de la méthode d'appel, puis transmettez cette chaîne au gestionnaire d'événements lorsque vous la déclenchez:

private static string GetCaller([System.Runtime.CompilerServices.CallerMemberName] string s = null) => s;

Option 3. (Moins rapide mais toujours aussi rapide) Dans votre gestionnaire d'événements lorsque vous le déclenchez, obtenez la chaîne du nom de la méthode d'appel avec ceci:

string callingMethod = new System.Diagnostics.StackTrace().GetFrame(1).GetMethod().ReflectedType.Name.Split('<', '>')[1];

Se désabonner des événements

Vous pouvez avoir un scénario dans lequel votre événement personnalisé comporte plusieurs gestionnaires d’événements, mais vous souhaitez en supprimer un spécial de la liste des gestionnaires d’événements. Pour ce faire, utilisez le -= opérateur comme ça:

MyEvent -= MyEventHandler;

Un mot de prudence mineure avec cela, cependant. Si vous faites cela et que cet événement n'a plus de gestionnaire d'événement et que vous le déclenchez à nouveau, une exception sera levée. (Des exceptions, bien sûr, vous pouvez piéger avec des blocs try/catch.)

Effacer tous les événements

Ok, supposons que vous ayez terminé avec les événements et que vous ne voulez plus en traiter. Il suffit de le définir sur null comme suit:

MyEvent = null;

La même mise en garde pour les événements de désinscription est également ici. Si votre gestionnaire d'événements personnalisé n'a plus d'événements et que vous le déclenchez à nouveau, votre programme lève une exception.

12
Volomike

Comme cela a déjà été mentionné, le champ de progression a besoin du mot-clé event

public event EventHandler<Progress> progress;

Mais je ne pense pas que ce soit là que vous souhaitiez réellement votre événement. Je pense que vous voulez réellement l'événement dans TestClass. A quoi ressemble ce qui suit? (Je n'ai jamais vraiment essayé de configurer des événements statiques, donc je ne sais pas si ce qui suit va compiler ou non, mais je pense que cela vous donne une idée du modèle que vous devriez viser.)

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        TestClass.progress += SetStatus;
    }

    private void SetStatus(object sender, Progress e)
    {
        label1.Text = e.Status;
    }

    private void button1_Click_1(object sender, EventArgs e)
    {
         TestClass.Func();
    }

 }

public class TestClass
{
    public static event EventHandler<Progress> progress; 

    public static void Func()
    {
        //time consuming code
        OnProgress(new Progress("current status"));
        // time consuming code
        OnProgress(new Progress("some new status"));            
    }

    private static void OnProgress(EventArgs e) 
    {
       if (progress != null)
          progress(this, e);
    }
}


public class Progress : EventArgs
{
    public string Status { get; private set; }

    private Progress() {}

    public Progress(string status)
    {
        Status = status;
    }
}
9
Josh Russo