Verarbeiten und Auslösen von Ereignissen
Ereignisse in .NET basieren auf dem Delegatmodell. Das Delegatmodell folgt dem Beobachterentwurfsmuster, mit dem sich ein Abonnent bei einem Anbieter registrieren und Benachrichtigungen von diesem empfangen kann. Von einem Ereignissender wird eine Benachrichtigung erstellt, die angibt, dass ein Ereignis aufgetreten ist. Diese Benachrichtigung wird dann vom Ereignisempfänger empfangen, und eine Antwort wird definiert. In diesem Artikel werden die Hauptkomponenten des Delegatmodells, das Verwenden von Ereignissen in Anwendungen und das Implementieren von Ereignissen im Code beschrieben.
Ereignisse
Ein Ereignis ist eine Meldung, die von einem Objekt gesendet wird, um das Auftreten einer Aktion zu signalisieren. Die Aktion kann durch Benutzerinteraktionen wie das Klicken auf eine Schaltfläche verursacht werden, oder sie kann durch eine andere Programmlogik, z. B. das Ändern eines Eigenschaftswerts, ausgelöst werden. Das Objekt, von dem das Ereignis ausgelöst wird, wird als Ereignissender bezeichnet. Dem Ereignissender ist nicht bekannt, welches Objekt oder welche Methode die ausgelösten Ereignisse empfangen (behandeln) wird. Das Ereignis ist in der Regel ein Member des Ereignissenders. Beispielsweise ist das Click-Ereignis ein Member der Klasse Button, und das PropertyChanged-Ereignis ist ein Member der Klasse, von der die INotifyPropertyChanged-Schnittstelle implementiert wird.
Zum Definieren eines Ereignisses verwenden Sie entweder das Schlüsselwort event
(in C#) oder das Schlüsselwort Event
(in Visual Basic) in der Signatur der Ereignisklasse und geben den Typ des Delegaten für das Ereignis an. Delegaten werden im nächsten Abschnitt erläutert.
In der Regel fügen Sie zum Auslösen eines Ereignisses eine Methode hinzu, die als protected
und virtual
(in C#) bzw. Protected
und Overridable
(in Visual Basic) gekennzeichnet ist. Nennen Sie diese Methode On
EventName (zum Beispiel OnDataReceived
). Von dieser Methode muss ein Parameter akzeptiert werden, der ein Ereignisdatenobjekt angibt, welches ein Objekt des Typs EventArgs oder eines abgeleiteten Typs ist. Sie stellen diese Methode bereit, damit abgeleitete Klassen die Logik zum Auslösen des Ereignisses überschreiben können. Eine abgeleitete Klasse sollte immer die On
EventName-Methode der Basisklasse aufrufen, um sicherzustellen, dass registrierte Delegaten das Ereignis empfangen.
Im folgenden Beispiel wird die Deklaration eines Ereignisses namens ThresholdReached
erläutert. Das Ereignis wird dem EventHandler-Delegaten zugeordnet, und es wird in einer Methode namens OnThresholdReached
ausgelöst.
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
Delegaten
Ein Delegat ist ein Typ, der einen Verweis auf eine Methode enthält. Ein Delegat wird mit einer Signatur deklariert, die den Rückgabetyp und die Parameter für die Methoden angibt, auf die er verweist. Er kann nur Verweise auf Methoden enthalten, die mit der Signatur übereinstimmen. Ein Delegat entspricht insofern einem typsicheren Funktionszeiger oder einem Rückruf. Mit einer Delegatdeklaration ist eine Delegatklasse ausreichend definiert.
Delegaten können in .NET vielfältig verwendet werden. Im Kontext der Ereignisse ist ein Delegat ein Mittler (oder ein zeigerähnlicher Mechanismus) zwischen der Ereignisquelle und dem Code, mit dem das Ereignis behandelt wird. Sie weisen einen Delegaten einem Ereignis zu, indem Sie den Delegattyp in der Ereignisdeklaration, wie im Beispiel des vorherigen Abschnitts veranschaulicht, einschließen. Weitere Informationen zu Delegaten finden Sie unter der Delegate-Klasse.
.NET stellt die Delegaten EventHandler und EventHandler<TEventArgs> zur Unterstützung der meisten Ereignisszenarien bereit. Verwenden Sie den EventHandler-Delegaten für alle Ereignisse, in denen keine Ereignisdaten enthalten sind. Verwenden Sie den EventHandler<TEventArgs>-Delegaten für Ereignisse, die Daten über das Ereignis enthalten. Diese Delegaten verfügen über keinen Rückgabetypwert und akzeptieren zwei Parameter (ein Objekt für die Ereignisquelle sowie ein Objekt für Ereignisdaten).
Delegaten sind Multicastdelegaten, d.h., sie können Verweise auf mehrere Methoden für die Ereignisbehandlung enthalten. Weitere Informationen finden Sie auf der Delegate-Referenzseite. Delegaten bieten Flexibilität und eine genaue Steuerung bei der Ereignisbehandlung. Ein Delegat fungiert als ein Ereignisverteiler für die Klasse, die das Ereignis auslöst, indem er eine Liste der registrierten Ereignishandler für das Ereignis verwaltet.
Für Szenarien, in denen die Delegaten EventHandler und EventHandler<TEventArgs> nicht funktionieren, können Sie einen Delegaten definieren. Szenarien, für die Sie einen Delegaten definieren müssen, sind sehr selten, z. B. bei der Arbeit mit Code, von dem keine Generics erkannt werden. Markieren Sie einen Delegaten mit dem Schlüsselwort delegate
(in C#) und dem Schlüsselwort Delegate
(in Visual Basic) in der Deklaration. Im folgenden Beispiel wird die Deklaration eines Delegaten namens ThresholdReachedEventHandler
erläutert.
public delegate void ThresholdReachedEventHandler(object sender, ThresholdReachedEventArgs e);
Public Delegate Sub ThresholdReachedEventHandler(sender As Object, e As ThresholdReachedEventArgs)
Ereignisdaten
Daten, die einem Ereignis zugewiesen sind, können durch eine Ereignisdatenklasse bereitgestellt werden. In .NET werden viele Ereignisdatenklassen für die Verwendung in Ihren Anwendungen bereitgestellt. Zum Beispiel ist die SerialDataReceivedEventArgs-Klasse die Ereignisdatenklasse für das SerialPort.DataReceived-Ereignis. .NET folgt einem Benennungsmuster, bei dem alle Ereignisdatenklassen auf EventArgs
enden. Sie bestimmen, welche Ereignisdatenklasse einem Ereignis zugeordnet wird, indem Sie den Delegaten nach dem Ereignis durchsuchen. Zum Beispiel enthält der SerialDataReceivedEventHandler-Delegat die SerialDataReceivedEventArgs-Klasse als einen seiner Parameter.
Die EventArgs-Klasse ist der Basistyp aller Ereignisdatenklassen. EventArgs ist auch die Klasse, die bei einem Ereignis verwendet wird, dem keine Daten zugeordnet sind. Wenn Sie ein Ereignis erstellen, nur um andere Klassen über ein Geschehnis zu benachrichtigen, ohne dass Daten übergeben werden, schließen Sie die EventArgs-Klasse als zweiten Parameter im Delegaten ein. Sie können den EventArgs.Empty-Wert übergeben, wenn keine Daten bereitgestellt werden. Im EventHandler-Delegat ist die EventArgs-Klasse als Parameter enthalten.
Wenn Sie eine benutzerdefinierte Ereignisdatenklasse erstellen möchten, erstellen Sie eine von EventArgs abgeleitete Klasse, und stellen Sie dann alle Member bereit, die zum Übergeben der mit dem Ereignis verknüpften Daten erforderlich sind. In der Regel sollten Sie dem Benennungsmuster von .NET folgen und den Ereignisdaten-Klassennamen auf EventArgs
enden lassen.
Im folgenden Beispiel wird eine Ereignisdatenklasse ThresholdReachedEventArgs
veranschaulicht. Darin sind Eigenschaften enthalten, die für das ausgelöste Ereignis spezifisch sind.
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
Ereignishandler
Um auf ein Ereignis zu reagieren, definieren Sie eine Ereignishandlermethode im Ereignisempfänger. Diese Methode muss der Signatur des Delegaten für das von Ihnen behandelte Ereignis entsprechen. Im Ereignishandler führen Sie die Aktionen aus, die beim Auslösen des Ereignisses erforderlich sind, zum Beispiel das Sammeln von Benutzereingaben, nachdem der Benutzer auf eine Schaltfläche geklickt hat. Um bei Auftreten des Ereignisses Benachrichtigungen zu empfangen, muss die Ereignishandlermethode das Ereignis abonnieren.
Im folgenden Beispiel wird die Ereignishandlermethode c_ThresholdReached
dargestellt, die der Signatur für den EventHandler-Delegaten entspricht. Die Methode abonniert das ThresholdReached
-Ereignis.
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
Statische und dynamische Ereignishandler
Mit .NET können sich Abonnenten entweder statisch oder dynamisch für Ereignisbenachrichtigungen registrieren. Statische Ereignishandler sind für die gesamte Lebensdauer der Klasse gültig, deren Ereignisse sie behandeln. Dynamische Ereignishandler werden bei der Programmausführung explizit aktiviert und deaktiviert. Dies erfolgt in der Regel als Reaktion auf eine bedingte Programmlogik. So können sie beispielsweise verwendet werden, wenn Ereignisbenachrichtigungen nur unter bestimmten Bedingungen erforderlich sind, oder wenn eine Anwendung mehrere Ereignishandler bereitstellt und über die Laufzeitbedingungen definiert wird, welcher davon verwendet wird. Im Beispiel des vorherigen Abschnitts wird das dynamische Hinzufügen eines Ereignishandlers veranschaulicht. Weitere Informationen finden Sie unter Ereignisse (Visual Basic) und Ereignisse (C#-Programmierhandbuch).
Auslösen mehrerer Ereignisse
Wenn von der Klasse mehrere Ereignisse ausgelöst werden, generiert der Compiler ein Feld pro Ereignisdelegatinstanz. Ist die Anzahl der Ereignisse sehr hoch, wird u. U. zu viel Speicher beansprucht, wenn für jeden Delegaten ein Feld generiert wird. Für solche Situationen werden in .NET Ereigniseigenschaften bereitgestellt, die Sie mit einer weiteren beliebig wählbaren Datenstruktur zum Speichern von Ereignisdelegaten verwenden können.
Ereigniseigenschaften bestehen aus Ereignisdeklarationen, die von Ereignisaccessoren begleitet werden. Ereignisaccessoren sind die von Ihnen definierten Methoden, mit denen Ereignisdelegatinstanzen der Speicherdatenstruktur hinzugefügt oder daraus entfernt werden können. Beachten Sie, dass Ereigniseigenschaften langsamer als Ereignisfelder sind, da jeder Ereignisdelegat abgerufen werden muss, bevor er aufgerufen werden kann. Sie müssen daher einen Kompromiss zwischen hoher Speicherauslastung und verminderter Geschwindigkeit finden. Wenn die Klasse viele Ereignisse definiert, die selten ausgelöst werden, können Sie Ereigniseigenschaften implementieren. Weitere Informationen finden Sie unter Vorgehensweise: Behandeln mehrerer Ereignisse mit Ereigniseigenschaften.
Verwandte Artikel
Titel | Beschreibung |
---|---|
How to: Auslösen und Behandeln von Ereignissen | In diesem Abschnitt sind Beispiele zum Auslösen und Verarbeiten von Ereignissen enthalten. |
How to: Behandeln mehrerer Ereignisse mit Ereigniseigenschaften | In diesem Abschnitt wird die Verwendung von Ereigniseigenschaften zum Behandeln mehrerer Ereignisse veranschaulicht. |
Beobachterentwurfsmuster | Das Entwurfsmuster, mit dem sich ein Abonnent bei einem Anbieter registrieren und Benachrichtigungen von diesem empfangen kann, wird beschrieben. |