Déclenchement d'un événement
Pour que votre classe déclenche un événement, vous devez fournir les trois éléments suivants :
une classe qui fournit les données d'événement ;
un délégué d'événement ;
la classe qui déclenche l'événement.
Définition d'une classe pour fournir les données d'événement
Par convention dans le .NET Framework, lorsqu'un événement est déclenché, il passe les données d'événement à ses gestionnaires d'événements. Les données d'événement sont fournies par la classe System.EventArgs ou par une classe qui en est dérivée.
Dans de nombreux cas, un événement n'a pas de données personnalisées ; le fait que l'événement ait été déclenché fournit toutes les informations requises par les gestionnaires d'événements. Dans ce cas, l'événement peut passer un objet EventArgs à ses gestionnaires. La classe EventArgs n'a qu'un seul membre, Empty, qui n'est pas hérité de System.Object. Il peut être utilisé pour instancier une nouvelle classe EventArgs.
Si un événement a des données personnalisées, il peut passer une instance d'une classe dérivée de EventArgs aux gestionnaires d'événements. En fonction des données précises que l'événement passe aux gestionnaires, il se peut que vous puissiez utiliser une classe de données d'événement existante dans le .NET Framework. Par exemple, si votre gestionnaire d'événements autorise l'annulation de l'action associée à l'événement, vous pouvez utiliser la classe CancelEventArgs.
Lorsque vous devez fournir des données personnalisées aux gestionnaires et qu'aucune classe existante n'est disponible, vous pouvez définir votre propre classe de données d'événement. Elle doit dériver de System.EventArgs. Par convention, cette classe est nommée EventNameEventArgs. L'exemple suivant illustre une telle classe de données d'événement personnalisée. Il définit une classe nommée AlarmEventArgs qui fournit deux éléments de données aux gestionnaires d'événements : la propriété Time en lecture seule, qui indique quand l'alarme se déclenche, et la propriété Snooze, qui indique si l'alarme doit se déclencher à nouveau après un intervalle désigné ou si les alarmes ultérieures doivent être annulées.
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; }
}
};
Définition d'un délégué pour l'événement
Un délégué d'événement est utilisé pour définir la signature de l'événement. Un délégué d'événement particulier correspond généralement à une classe de données d'événement particulière. Par convention, dans le .NET Framework, les événements ont la signature EventName(sender, e), où sender est un Object qui fournit une référence à la classe ou la structure qui a déclenché l'événement, et e est un objet EventArgs ou un objet dérivé de EventArgs qui fournit les données d'événement. Généralement, la définition de délégué prend alors la forme EventNameHandler(sender, e).
Si vous utilisez une classe de données d'événement qui est déjà définie dans la bibliothèque de classes .NET Framework ou dans une bibliothèque tierce, il est possible qu'un délégué d'événement correspondant soit également défini dans cette bibliothèque. Par exemple, le délégué EventHandler peut être utilisé avec la classe EventArgs. De même, le délégué CancelEventHandler peut être utilisé avec la classe CancelEventArgs.
Si vous définissez une classe de données d'événement personnalisée, vous pouvez également définir un délégué personnalisé pour définir la signature d'événement, ou utiliser le délégué Action<T1, T2> générique.
L'exemple suivant définit un délégué d'événement nommé AlarmEventHandler.
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);
Définition d'une classe pour déclencher l'événement
La classe qui déclenche l'événement doit fournir la déclaration de l'événement et définir une méthode qui déclenche l'événement. De plus, elle doit fournir une certaine logique pour déclencher l'événement dans une propriété ou une méthode de classe.
Vous définissez un membre d'événement dans votre classe à l'aide du mot clé event en C# ou l'instruction Event en Visual Basic. Lorsque le compilateur rencontre une déclaration d'événement dans votre classe, il crée un membre privé, par exemple :
private EventNameHandler eh = null;
Le compilateur crée également les deux méthodes publiques add_EventName et remove_EventName. Ces méthodes sont des connexions d'événement qui permettent aux délégués d'être combinés au délégué d'événement eh ou d'en être supprimés. Les détails sont masqués dans le programmeur.
Notes
Dans d'autres langages que C# et Visual Basic 2005, le compilateur peut ne pas générer automatiquement le code correspondant à un membre d'événement et vous pouvez être amené à définir explicitement les connexions d'événement et le champ délégué privé.
L'exemple suivant déclare un événement nommé AlarmEvent. Il est extrait de l'exemple fourni pour une classe nommée Alarm dont le code source complet est indiqué ci-dessous. Notez qu'il a la signature du délégué AlarmEventHandler.
Event AlarmEvent As AlarmEventHandler
public event AlarmEventHandler AlarmEvent;
public:
event AlarmEventHandler^ AlarmEvent;
Une fois que vous avez défini votre implémentation d'événement, vous devez déterminer quand déclencher l'événement. Vous déclenchez l'événement en appelant la méthode protégée OnEventName dans la classe qui a défini l'événement, ou dans une classe dérivée. La méthode OnEventName déclenche alors l'événement.
Notes
La méthode protégée OnEventName permet également aux classes dérivées de substituer l'événement sans y attacher de délégué.Une classe dérivée doit toujours appeler la méthode OnEventName de la classe de base pour que les délégués inscrits puissent recevoir l'événement.
L'exemple suivant définit la méthode OnAlarmEvent, qui est chargée du déclenchement de l'événement AlarmEvent.
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);
}
L'exemple suivant définit une méthode nommée Set qui contient la logique à utiliser pour déclencher l'événement en appelant la méthode OnAlarmEvent. Si les heures et les minutes de l'heure de l'alarme sont égales aux heures et aux minutes de l'heure actuelle, la méthode Set instancie un objet AlarmEventArgs et lui fournit l'heure à laquelle l'alarme s'est déclenchée. Une fois l'exécution des gestionnaires d'événements terminée, elle vérifie la valeur de la propriété Snooze. Si Snooze a la valeur false, aucun autre événement d'alarme ne doit être déclenché. La méthode Set peut se terminer. Si Snooze a la valeur true, l'heure à laquelle l'alarme doit être déclenchée est incrémentée de la valeur de la propriété Interval.
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);
}
L'exemple suivant inclut la totalité du code source pour la classe Alarm.
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);
}
};
Voir aussi
Tâches
Comment : déclencher et utiliser des événements
Comment : implémenter des événements dans votre classe