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

Konzepte

Ereignisse und Delegaten

Weitere Ressourcen

Behandeln und Auslösen von Ereignissen