Ich versuche, benutzerdefinierte Ereignisse zu lernen, und ich habe versucht, eines zu erstellen, aber es scheint, als hätte ich ein Problem
Ich habe ein Formular, eine statische Klasse und ein benutzerdefiniertes Ereignis erstellt. Ich versuche zu erreichen, dass durch Drücken der Taste Form die statische Klassenfunktion aufgerufen wird und dann von Zeit zu Zeit ein Ereignis ausgelöst wird, um den aktuellen Status zu melden. Form1 hört zu, wenn das Ereignis ausgelöst wird, und wenn dies der Fall ist, ändert es den Text von label1
Folgendes habe ich bisher
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();
}
}
Datei 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;
}
}
Was ich jetzt nicht verstehe, ist, wie ich ein Ereignis aus TestClass auslösen kann, damit Form1 das Ereignis verarbeiten und label.Text ändern kann
RaiseProgress()
, die das Ereignis auslöst, aber ich bin mir nicht sicher, ob dies eine gute Idee ist.Antworten:
Dies ist eine einfache Möglichkeit, benutzerdefinierte Ereignisse zu erstellen und diese auszulösen. Sie erstellen einen Delegaten und ein Ereignis in der Klasse, aus der Sie werfen. Abonnieren Sie dann das Ereignis aus einem anderen Teil Ihres Codes. Sie haben bereits eine benutzerdefinierte Ereignisargumentklasse, sodass Sie darauf aufbauen können, um andere Ereignisargumentklassen zu erstellen. NB: Ich habe diesen Code nicht kompiliert.
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; } }
quelle
UpdateStatus
Funktion, die verwirrend sein kann. Ich würde die Funktion aus Gründen der Übersichtlichkeit lieberForm1
mit einem anderen Namen aufrufenProcessUpdateStatusEvent
. Ansonsten sehr gute Erklärung.Sie haben kein Ereignis erstellt. Um das zu tun, schreibe:
public event EventHandler<Progress> Progress;
Anschließend können Sie
Progress
innerhalb der Klasse aufrufen, in der sie als normale Funktion oder als Delegat deklariert wurde:Progress(this, new Progress("some status"));
Wenn Sie also den Fortschritt in melden möchten
TestClass
, sollte das Ereignis ebenfalls vorhanden und statisch sein. Sie können es von Ihrem Formular aus wie folgt abonnieren:Außerdem sollten Sie wahrscheinlich umbenennen
Progress
zuProgressEventArgs
, so dass es ist klar , was es ist.quelle
Ereignisse sind in C # ziemlich einfach, aber die MSDN-Dokumente machen sie meiner Meinung nach ziemlich verwirrend. Normalerweise wird in den meisten Dokumentationen erläutert, wie eine Klasse von der
EventArgs
Basisklasse geerbt wird, und dafür gibt es einen Grund . Es ist jedoch nicht der einfachste Weg, Events zu machen, und für jemanden, der schnell und einfach etwas möchte, und in einer Zeitkrise ist die Verwendung desAction
Typs Ihr Ticket.Ereignisse erstellen und abonnieren
1. Erstellen Sie Ihre Veranstaltung direkt nach Ihrer
class
Erklärung in Ihrer Klasse .public event Action<string,string,string,string>MyEvent;
2. Erstellen Sie Ihre Event-Handler-Klassenmethode in Ihrer Klasse.
private void MyEventHandler(string s1,string s2,string s3,string s4) { Console.WriteLine("{0} {1} {2} {3}",s1,s2,s3,s4); }
3. Wenn Ihre Klasse aufgerufen wird, weisen Sie sie an, das Ereignis mit Ihrem neuen Ereignishandler zu verbinden. Der Grund, warum der
+=
Operator verwendet wird, liegt darin, dass Sie Ihren speziellen Ereignishandler an das Ereignis anhängen. Sie können dies tatsächlich mit mehreren separaten Ereignishandlern tun. Wenn ein Ereignis ausgelöst wird, wird jeder Ereignishandler in der Reihenfolge ausgeführt, in der Sie sie hinzugefügt haben.class Example { public Example() // I'm a C# style class constructor { MyEvent += new Action<string,string,string,string>(MyEventHandler); } }
4. Wenn Sie bereit sind, lösen Sie das Ereignis irgendwo in Ihrem Klassencode wie folgt aus (auch bekannt als Raise):
MyEvent("wow","this","is","cool");
Das Endergebnis, wenn Sie dies ausführen, ist, dass die Konsole "Wow, das ist cool" ausgibt. Wenn Sie "cool" mit einem Datum oder einer Sequenz geändert und diesen Ereignisauslöser mehrmals ausgeführt haben, wird das Ergebnis in einer FIFO-Sequenz angezeigt, wie Ereignisse normalerweise funktionieren sollten.
In diesem Beispiel habe ich 4 Zeichenfolgen übergeben. Sie können diese jedoch in einen akzeptablen Typ ändern oder mehr oder weniger Typen verwenden oder sogar das
<...>
Out entfernen und nichts an Ihren Event-Handler übergeben.Wenn Sie mehrere benutzerdefinierte Ereignishandler hätten und diese alle mit dem
+=
Operator für Ihr Ereignis abonniert hätten, hätte Ihr Ereignisauslöser sie alle nacheinander aufgerufen.Ereignisanrufer identifizieren
Was aber, wenn Sie den Anrufer für dieses Ereignis in Ihrem Ereignishandler identifizieren möchten? Dies ist nützlich, wenn Sie einen Ereignishandler wünschen, der mit Bedingungen reagiert, die darauf basieren, wer das Ereignis ausgelöst / ausgelöst hat. Es gibt einige Möglichkeiten, dies zu tun. Nachfolgend finden Sie Beispiele, die in der Reihenfolge ihrer Schnelligkeit angezeigt werden:
Option 1. (Schnellste) Wenn Sie es bereits kennen, übergeben Sie den Namen als Literalzeichenfolge an den Ereignishandler, wenn Sie ihn auslösen.
Option 2. (etwas schnell) Fügen Sie dies Ihrer Klasse hinzu und rufen Sie es über die aufrufende Methode auf. Übergeben Sie diese Zeichenfolge dann an den Ereignishandler, wenn Sie sie auslösen:
private static string GetCaller([System.Runtime.CompilerServices.CallerMemberName] string s = null) => s;
Option 3. (Am wenigsten schnell, aber immer noch schnell) Rufen Sie in Ihrem Ereignishandler beim Auslösen die Zeichenfolge für den Namen der aufrufenden Methode folgendermaßen ab:
string callingMethod = new System.Diagnostics.StackTrace().GetFrame(1).GetMethod().ReflectedType.Name.Split('<', '>')[1];
Abmelden von Ereignissen
Möglicherweise haben Sie ein Szenario, in dem Ihr benutzerdefiniertes Ereignis mehrere Ereignishandler enthält, Sie möchten jedoch einen speziellen aus der Liste der Ereignishandler entfernen. Verwenden Sie dazu den
-=
Operator wie folgt:Ein Wort der kleinen Vorsicht. Wenn Sie dieses und jenes Ereignis ausführen und keine Ereignishandler mehr haben und dieses Ereignis erneut auslösen, wird eine Ausnahme ausgelöst. (Ausnahmen können Sie natürlich mit Try / Catch-Blöcken abfangen.)
Alle Ereignisse löschen
Okay, nehmen wir an, Sie sind mit Ereignissen fertig und möchten nicht mehr verarbeiten. Setzen Sie es einfach wie folgt auf null:
MyEvent = null;
Die gleiche Vorsicht gilt auch für das Abbestellen von Ereignissen. Wenn Ihr benutzerdefinierter Ereignishandler keine Ereignisse mehr enthält und Sie ihn erneut auslösen, löst Ihr Programm eine Ausnahme aus.
quelle
Wie bereits erwähnt, benötigt das Fortschrittsfeld das Keyword-Ereignis
public event EventHandler<Progress> progress;
Aber ich glaube nicht, dass Sie dort Ihre Veranstaltung haben wollen. Ich denke, Sie wollen die Veranstaltung tatsächlich in
TestClass
. Wie sieht das folgende aus? (Ich habe noch nie versucht, statische Ereignisse einzurichten, daher bin ich mir nicht sicher, ob das Folgende kompiliert wird oder nicht, aber ich denke, dies gibt Ihnen eine Vorstellung von dem Muster, das Sie anstreben sollten.)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; } }
quelle