Auslösen eines Ereignisses
Klassen, die ein Ereignis auslösen sollen, müssen diese drei Elemente bereitstellen:
Eine Klasse, die Ereignisdaten enthält.
Einen Ereignisdelegaten.
Die Klasse, die das Ereignis auslöst.
Definieren einer Klasse zum Bereitstellen von Ereignisdaten
Üblicherweise werden Ereignisdaten beim Auslösen eines Ereignisses in .NET Framework an die Ereignishandler übergeben. Die Ereignisdaten werden von der System.EventArgs-Klasse oder einer davon abgeleiteten Klasse bereitgestellt.
Ereignisse weisen i. d. R. keine benutzerdefinierten Daten auf; das Auslösen des Ereignisses stellt alle erforderlichen Informationen für Ereignishandler bereit. In diesem Fall kann das Ereignis ein EventArgs-Objekt an die entsprechenden Handler übergeben. Die EventArgs-Klasse weist nur den Member Empty auf; dieser wird nicht von System.Object geerbt. Sie kann zum Instanziieren einer neuen EventArgs-Klasse verwendet werden.
Ereignisse, die benutzerdefinierte Daten aufweisen, können eine Instanz einer Klasse an Ereignishandler übergeben, die von EventArgs abgeleitet wurde. Je nachdem, welche Daten genau vom Ereignis an Handler übergeben werden, können Sie möglicherweise eine vorhandene Ereignisdatenklasse in .NET Framework verwenden. Wenn der Ereignishandler beispielsweise das Abbrechen der Aktion ermöglicht, die dem Ereignis zugeordnet ist, können Sie die CancelEventArgs-Klasse verwenden.
Wenn Sie benutzerdefinierte Daten für Handler bereitstellen müssen und keine vorhandene Klasse verfügbar ist, können Sie eine eigene Ereignisdatenklasse definieren. Diese muss von System.EventArgs abgeleitet werden. Der Name dieser Klasse lautet standardmäßig EventNameEventArgs. Im folgenden Beispiel wird eine entsprechende benutzerdefinierte Ereignisdatenklasse veranschaulicht. Im Beispiel wird die AlarmEventArgs-Klasse definiert, die zwei Datenelemente für Ereignishandler bereitstellt: die schreibgeschützte Time-Eigenschaft, die angibt, wann der Alarm ausgelöst wurde, und die Snooze-Eigenschaft, die angibt, ob der Alarm nach Ablauf eines festgelegten Zeitraums erneut ausgelöst werden soll.
Public Class AlarmEventArgs : Inherits EventArgs
Private alarmTime As Date
Private snoozeOn As Boolean = True
Public Sub New(time As Date)
Me.alarmTime = time
End Sub
Public ReadOnly Property Time As Date
Get
Return Me.alarmTime
End Get
End Property
Public Property Snooze As Boolean
Get
Return Me.snoozeOn
End Get
Set
Me.snoozeOn = value
End Set
End Property
End Class
public class AlarmEventArgs : EventArgs
{
private DateTime alarmTime;
private bool snoozeOn = true;
public AlarmEventArgs(DateTime time)
{
this.alarmTime = time;
}
public DateTime Time
{
get { return this.alarmTime; }
}
public bool Snooze
{
get { return this.snoozeOn; }
set { this.snoozeOn = value; }
}
}
public ref class AlarmEventArgs : public EventArgs
{
private:
System::DateTime^ alarmTime;
bool snoozeOn;
public:
AlarmEventArgs(System::DateTime^ time)
{
this->alarmTime = time;
this->snoozeOn = true;
}
property DateTime^ Time
{
System::DateTime^ get()
{ return this->alarmTime; }
}
property bool Snooze
{
bool get()
{ return this->snoozeOn; }
void set(bool snooze)
{ this->snoozeOn = snooze; }
}
};
Definieren eines Delegaten für das Ereignis
Ereignisdelegaten werden verwendet, um die Signatur des Ereignisses zu definieren. Ein bestimmter Ereignisdelegat entspricht i. d. R. einer bestimmten Ereignisdatenklasse. Ereignisse in .NET Framework weisen üblicherweise die Signatur EventName(sender, e) auf. sender stellt dabei ein Object dar, das einen Verweis auf die Klasse oder Struktur enthält, die das Ereignis ausgelöst hat; e stellt ein EventArgs-Objekt oder ein Objekt dar, das von EventArgs abgeleitet wurde und Ereignisdaten bereitstellt. Die Delegatdefinition weist i. d. R. das Format EventName Handler(sender, e) auf.
Wenn Sie eine Ereignisdatenklasse verwenden, die bereits in der .NET Framework-Klassenbibliothek oder in der Bibliothek eines Drittanbieters definiert ist, ist wahrscheinlich auch bereits ein entsprechender Ereignisdelegat in dieser Bibliothek definiert. Beispielsweise kann der EventHandler-Delegat zusammen mit der EventArgs-Klasse verwendet werden. Analog kann der CancelEventHandler-Delegat mit der CancelEventArgs-Klasse verwendet werden.
Wenn Sie eine benutzerdefinierte Ereignisdatenklasse definieren, können Sie auch einen benutzerdefinierten Delegaten definieren, um die Ereignissignatur anzugeben, oder Sie können den generischen Action<T1, T2>-Delegaten verwenden.
Im folgenden Beispiel wird der Ereignisdelegat AlarmEventHandler definiert.
Public Delegate Sub AlarmEventHandler(sender As Object, e As AlarmEventArgs)
public delegate void AlarmEventHandler(object sender, AlarmEventArgs e);
public delegate void AlarmEventHandler(System::Object^ sender, AlarmEventArgs^ e);
Definieren einer Klasse zum Auslösen des Ereignisses
Die Klasse, die das Ereignis auslöst, muss die Ereignisdeklaration bereitstellen und eine Methode angeben, die das Ereignis auslöst. Außerdem muss die Klasse Logik bereitstellen, um das Ereignis in einer Klasseneigenschaft oder einer Methode auszulösen.
Ereignismember in der Klasse werden mit dem event-Schlüsselwort in C# oder mit der Event-Anweisung in Visual Basic definiert. Wenn der Compiler eine Ereignisdeklaration in der Klasse vorfindet, erstellt er einen privaten Member wie den folgenden:
private EventNameHandler eh = null;
Der Compiler erstellt auch die öffentliche add_EventName-Methode und die öffentliche remove_EventName-Methode. Diese Methoden sind Ereignishooks, mit denen Delegaten kombiniert oder aus dem Ereignisdelegaten eh entfernt werden können. Die Details bleiben dem Programmierer verborgen.
Hinweis
In anderen Sprachen als C# und Visual Basic 2005 generiert der Compiler möglicherweise den Code zu einem Ereignismember nicht automatisch. Ereignishooks und das private Delegatfeld müssen daher ggf. explizit definiert werden.
Im folgenden Beispiel wird das Ereignis AlarmEvent deklariert. Es wird für die Alarm-Klasse aus dem Beispiel exzerpiert; der vollständige Quellcode ist nachfolgend angegeben. Beachten Sie, dass es die Signatur des AlarmEventHandler-Delegaten aufweist.
Event AlarmEvent As AlarmEventHandler
public event AlarmEventHandler AlarmEvent;
public:
event AlarmEventHandler^ AlarmEvent;
Sobald Sie die Ereignisimplementierung definiert haben, müssen Sie festlegen, wann das Ereignis ausgelöst werden soll. Sie lösen das Ereignis aus, indem Sie die geschützte OnEventName-Methode in einer abgeleiteten Klasse oder in der Klasse aufrufen, die das Ereignis definiert. Das Ereignis wird dann von der OnEventName-Methode ausgelöst.
Hinweis
Die geschützte OnEventName-Methode ermöglicht es abgeleiteten Klassen auch, das Ereignis ohne Anfügen eines Delegaten zu überschreiben.Eine abgeleitete Klasse muss immer die OnEventName-Methode der Basisklasse aufrufen, um sicherzustellen, dass registrierte Delegaten das Ereignis empfangen.
Im folgenden Beispiel wird die OnAlarmEvent-Methode definiert, die für das Auslösen des AlarmEvent-Ereignisses zuständig ist.
Protected Sub OnAlarmEvent(e As AlarmEventArgs)
RaiseEvent AlarmEvent(Me, e)
End Sub
protected void OnAlarmEvent(AlarmEventArgs e)
{
AlarmEvent(this, e);
}
protected:
void OnAlarmEvent(AlarmEventArgs^ e)
{
AlarmEvent(this, e);
}
Im folgenden Beispiel wird die Set-Methode definiert, die die Logik zum Auslösen des Ereignisses durch Aufrufen der OnAlarmEvent-Methode, enthält. Wenn die Stunden und Minuten des Alarmzeitpunkts den Stunden und Minuten der aktuellen Uhrzeit entsprechen, instanziiert die Set-Methode ein AlarmEventArgs-Objekt und gibt den Zeitpunkt an, zu dem der Alarm ausgelöst wurde. Nachdem die Ereignishandler ausgeführt wurden, wird der Wert der Snooze-Eigenschaft überprüft. Wenn Snooze gleich false ist, sollen keine weiteren Alarmereignisse ausgelöst werden, und die Set-Methode kann beendet werden. Wenn Snooze gleich true ist, wird der Zeitpunkt, zu dem der Alarm ausgelöst werden soll, um den Wert der Interval-Eigenschaft erhöht.
Public Sub [Set]()
Do
System.Threading.Thread.Sleep(2000)
Dim currentTime As DateTime = Date.Now
' Test whether it is time for the alarm to go off.
If currentTime.Hour = alarmTime.Hour And _
currentTime.Minute = AlarmTime.Minute Then
Dim args As New AlarmEventArgs(currentTime)
OnAlarmEvent(args)
If args.Snooze = False Then
Exit Sub
Else
Me.alarmTime = Me.alarmTime.AddMinutes(Me.interval)
End If
End If
Loop
End Sub
public void Set()
{
while (true) {
System.Threading.Thread.Sleep(2000);
DateTime currentTime = DateTime.Now;
// Test whether it is time for the alarm to go off.
if (currentTime.Hour == alarmTime.Hour &&
currentTime.Minute == alarmTime.Minute)
{
AlarmEventArgs args = new AlarmEventArgs(currentTime);
OnAlarmEvent(args);
if (! args.Snooze)
return;
else
this.alarmTime = this.alarmTime.AddMinutes(this.interval);
}
}
}
void Set()
{
do {
Thread::Sleep(2000);
System::DateTime^ currentTime = DateTime::Now;
// Test whether it's time for the alarm to go off.
if (currentTime->Hour == alarmTime->Hour && currentTime->Minute == alarmTime->Minute)
{
AlarmEventArgs^ args = gcnew AlarmEventArgs(currentTime);
OnAlarmEvent(args);
if (args->Snooze == false)
return;
else
this->alarmTime = this->alarmTime->AddMinutes(this->interval);
}
} while (true);
}
Im folgenden Beispiel finden Sie den vollständigen Quellcode für die Alarm-Klasse.
Public Class Alarm
Private alarmTime As Date
Private interval As Integer = 10
Event AlarmEvent As AlarmEventHandler
Public Sub New(time As Date)
Me.New(time, 10)
End Sub
Public Sub New(time As Date, interval As Integer)
Me.alarmTime = time
Me.interval = interval
End Sub
Public Sub [Set]()
Do
System.Threading.Thread.Sleep(2000)
Dim currentTime As DateTime = Date.Now
' Test whether it is time for the alarm to go off.
If currentTime.Hour = alarmTime.Hour And _
currentTime.Minute = AlarmTime.Minute Then
Dim args As New AlarmEventArgs(currentTime)
OnAlarmEvent(args)
If args.Snooze = False Then
Exit Sub
Else
Me.alarmTime = Me.alarmTime.AddMinutes(Me.interval)
End If
End If
Loop
End Sub
Protected Sub OnAlarmEvent(e As AlarmEventArgs)
RaiseEvent AlarmEvent(Me, e)
End Sub
End Class
public class Alarm
{
private DateTime alarmTime;
private int interval = 10;
public event AlarmEventHandler AlarmEvent;
public Alarm(DateTime time) : this(time, 10)
{
}
public Alarm(DateTime time, int interval)
{
this.alarmTime = time;
this.interval = interval;
}
public void Set()
{
while (true) {
System.Threading.Thread.Sleep(2000);
DateTime currentTime = DateTime.Now;
// Test whether it is time for the alarm to go off.
if (currentTime.Hour == alarmTime.Hour &&
currentTime.Minute == alarmTime.Minute)
{
AlarmEventArgs args = new AlarmEventArgs(currentTime);
OnAlarmEvent(args);
if (! args.Snooze)
return;
else
this.alarmTime = this.alarmTime.AddMinutes(this.interval);
}
}
}
protected void OnAlarmEvent(AlarmEventArgs e)
{
AlarmEvent(this, e);
}
}
public ref class Alarm
{
private:
System::DateTime^ alarmTime;
int interval;
public:
event AlarmEventHandler^ AlarmEvent;
Alarm(System::DateTime^ time) : alarmTime(time), interval(10) { };
Alarm(System::DateTime^ time, int interval) : alarmTime(time), interval(interval) {};
void Set()
{
do {
Thread::Sleep(2000);
System::DateTime^ currentTime = DateTime::Now;
// Test whether it's time for the alarm to go off.
if (currentTime->Hour == alarmTime->Hour && currentTime->Minute == alarmTime->Minute)
{
AlarmEventArgs^ args = gcnew AlarmEventArgs(currentTime);
OnAlarmEvent(args);
if (args->Snooze == false)
return;
else
this->alarmTime = this->alarmTime->AddMinutes(this->interval);
}
} while (true);
}
protected:
void OnAlarmEvent(AlarmEventArgs^ e)
{
AlarmEvent(this, e);
}
};
Siehe auch
Aufgaben
Gewusst wie: Auslösen und Behandeln von Ereignissen
Gewusst wie: Implementieren von Ereignissen in der Klasse