Contenu du cours
C# Avancé Avec .NET
C# Avancé Avec .NET
Événements Personnalisés
Dans le chapitre précédent, nous avons appris à lier des méthodes aux gestionnaires d'événements, mais est-il possible de créer nos propres événements ? Oui, en fait, c'est assez simple à faire.
Un système d'événements se compose de deux parties : la classe Éditeur et la classe Abonné. Il y a toujours une seule classe Éditeur pour un événement, cependant, il peut y avoir plusieurs classes Abonné.
Une classe Éditeur contient le délégué du gestionnaire d'événements pour l'événement, et une méthode pour invoquer ce délégué chaque fois que cela est pertinent.
Une classe est appelée classe Abonné dans ce contexte si elle souscrit une méthode au gestionnaire d'événements de la classe Éditeur.
Le diagramme suivant montre le flux de processus d'un système d'événements :
Nous allons créer un système d'événements simple en partant du projet par défaut. À l'intérieur du fichier C#, nous créons d'abord une nouvelle classe appelée CounterEvent
qui va représenter la classe Éditeur, et elle va avoir une instance EventHandler que nous créons en utilisant le type EventHandler
déjà existant :
index
public class CounterEvent { public event EventHandler AtTensMultiple; }
Cette classe a également besoin d'une méthode pour invoquer le gestionnaire d'événements chaque fois que nécessaire. Nous pouvons créer un événement qui est déclenché chaque fois que la condition count % 10 == 0
est satisfaite, où count
est le nombre de fois que l'utilisateur a cliqué sur le CounterBtn
. Définissons d'abord la méthode d'invocation à l'intérieur de CounterEvent, nous l'appellerons CountCheck
car elle vérifiera essentiellement la valeur de count
chaque fois qu'elle est appelée et elle invoquera AtTensMultiple
lorsque la condition est satisfaite.
index
public class CounterEvent { public event EventHandler? AtTensMultiple; public void CountCheck(int count) { if(count % 10 == 0) { EventHandler? handler = AtTensMultiple; if(handler) { AtTensMultiple(this, new EventArgs()); } } } }
Ici, l'argument this
est passé pour représenter le sender
et new EventArgs()
représente une nouvelle instance d'une classe vide. Nous pouvons passer des données dans les méthodes qui se sont abonnées au gestionnaire d'événements, lorsque le gestionnaire d'événements est invoqué, en utilisant ce deuxième argument, cependant, comme nous passons EventArgs
qui est une classe vide, aucune donnée n'est passée. Nous verrons comment passer des données de cette manière dans un instant.
Maintenant que la méthode d'invocation est définie, notre classe éditeur est à peu près complète. Nous devons faire deux choses de plus :
- Créer une instance de la classe éditeur ;
- Appeler la méthode d'invocation pour la rendre fonctionnelle ;
Donc, d'abord, je vais créer une instance à l'intérieur de la classe MainPage:
index
public static CounterEvent counter = new CounterEvent();
Et maintenant, appelons cette méthode à l'intérieur de OnCounterClicked
afin qu'elle effectue une vérification chaque fois que l'utilisateur clique sur le bouton.
index
private void OnCounterClicked(object? sender, new EventArgs e) { count++; if(count == 0) CounterBtn.Text = $"Clicked {count} time"; else CounterBtn.Text = $"Clicked {count} times"; counter.CounterCheck(count); }
Maintenant que notre événement est fonctionnel, nous sommes prêts à lier une méthode au gestionnaire d'événements. Je vais créer une nouvelle méthode appelée Reformat
qui ajoute simplement le texte (Ten's Multiple)
à la fin du texte du bouton chaque fois que la méthode est invoquée. Notre code complet ressemblera à ceci maintenant :
index
using System.Runtime.CompilerServices; namespace EventsIntro { public class CounterEvent { public event EventHandler? AtTensMultiple; public void CountCheck(int count) { EventHandler? handler = AtTensMultiple; if (handler != null) { if (count % 10 == 0) { handler(this, new EventArgs()); } } } } public partial class MainPage : ContentPage { int count = 0; CounterEvent counter = new CounterEvent(); public MainPage() { InitializeComponent(); CounterBtn.Clicked += OnCounterClicked; counter.AtTensMultiple += Reformat; } private void Reformat(object? sender, EventArgs e) { CounterBtn.Text += " " + "(Ten's Multiple)"; } private void OnCounterClicked(object? sender, EventArgs e) { count++; if (count == 1) CounterBtn.Text = $"Clicked {count} time"; else CounterBtn.Text = $"Clicked {count} times"; counter.CountCheck(count); } } }
Donc maintenant, si nous exécutons le programme et cliquons sur le bouton 10 fois, le texte (Ten's Multiple)
apparaîtra dans le texte du bouton. Si vous appuyez dessus 20 fois, la même chose se reproduira. Et ainsi de suite.
Maintenant, pour passer des arguments à la méthode Reformat
, nous pouvons créer une nouvelle classe appelée CustomEventArgs
dérivée de EventArgs
, et nous pouvons avoir certaines propriétés publiques dans cette classe qui peuvent représenter les paramètres :
index
public class CounterArgs : EventArgs { public string Text { get; } // Here 'Text' can act as a parameter or argument. public CounterArgs(string text) { this.Text = text; } }
Maintenant que nous avons une classe CustomEvenArgs
, nous devons apporter quelques modifications à la classe CounterEvent
:
index
public class CounterEvent { public delegate void CounterEventHandler(object sender, CounterArgs e); public event CounterEventHandler? AtTensMultiple; public void CountCheck(int count) { CounterEventHandler? handler = AtTensMultiple; if (handler != null) { if (count % 10 == 0) { handler(this, new CounterArgs("(something random)")); } } } }
Dans le code ci-dessus, nous créons d'abord une nouvelle définition pour le EventHandler et l'appelons CustomEventHandler
, où nous définissons le type de données du deuxième paramètre à CustomEventArgs
.
Deuxièmement, nous passons new CounterArgs("something random")
comme deuxième argument lors de l'appel du gestionnaire d'événements. Cela nous permet de passer la donnée de chaîne (something random)
comme argument à la méthode Refactor
, que nous pouvons accéder comme ceci :
index
// Modified signature to support 'CounterArgs' instead of 'EventArgs' private void Reformat(object? sender, CounterArgs e) { CounterBtn.Text += " " + e.Text; }
Donc, maintenant, notre code final devrait ressembler à ceci :
index
using System.Runtime.CompilerServices; namespace EventsIntro { public class CounterEvent { public delegate void CustomEventHandler(object? sender, CounterArgs e); public event CustomEventHandler? AtTensMultiple; public void CountCheck(int count) { CustomEventHandler? handler = AtTensMultiple; if (handler != null) { if (count % 10 == 0) { handler(this, new CounterArgs("(something random)")); } } } } public class CounterArgs : EventArgs { public string Text { get; } public CounterArgs(string text) { this.Text = text; } } public partial class MainPage : ContentPage { int count = 0; CounterEvent counter = new CounterEvent(); public MainPage() { InitializeComponent(); CounterBtn.Clicked += OnCounterClicked; counter.AtTensMultiple += Reformat; } private void Reformat(object? sender, CounterArgs e) { CounterBtn.Text += " " + e.Text; } private void OnCounterClicked(object? sender, EventArgs e) { count++; if (count == 1) CounterBtn.Text = $"Clicked {count} time"; else CounterBtn.Text = $"Clicked {count} times"; counter.CountCheck(count); } } }
Si vous exécutez le programme ci-dessus, le texte (something random)
sera ajouté à la fin du texte du bouton chaque fois que le count
est un multiple de dix. Ce qui indique que les données sont correctement transmises aux méthodes abonnées.
Points Importants :
- La Classe Émettrice contient la définition et une instance du délégué de gestionnaire d'événements personnalisé ;
- On peut sauter la définition du Délégué de Gestionnaire d'Événements si nous utilisons le type de délégué
EventHandler
pour créer l'instance ; - Il y a une méthode dans la Classe Émettrice qui est responsable de l'invocation du délégué chaque fois que c'est pertinent ;
- L'Instance du Délégué doit être publique pour la rendre accessible aux classes abonnées ;
- Nous pouvons passer des arguments dans les Méthodes de Gestionnaire d'Événements en créant notre propre classe qui dérive de
EventArgs
et en ayant des propriétés qui représentent les données ou les arguments que nous voulons passer ;
1. Quel mot-clé utilisons-nous pour convertir un délégué normal en gestionnaire d'événements ?
2. De quelle classe devons-nous hériter lors de la création d'arguments de méthode d'événement personnalisés ?
Merci pour vos commentaires !