2010-11-10 4 views
8

Je dois passer un événement en tant que paramètre à une fonction. Y-a-t'il une façon de le faire?VB.NET - Passer un événement en tant que paramètre

La raison en est que j'ai une séquence de deux lignes de code qui est jonchée partout dans mon programme, où je supprime dynamiquement le gestionnaire à un événement, puis définissez à nouveau le gestionnaire. Je le fais pour plusieurs événements différents et des gestionnaires d'événements, j'ai donc décidé d'écrire une fonction qui le fait. Par exemple, disons que j'ai un combobox dans mon code appelé combobox1, et j'ai le gestionnaire appelé indexChangedHandler. En plusieurs endroits de mon code, j'ai les deux lignes suivantes:

RemoveHandler combobox1.SelectedIndexChanged, AddressOf indexChangedHandler 
AddHandler combobox1.SelectedIndexChanged, AddressOf indexChangedHandler 

Maintenant, je ne veux pas continuer à répéter les deux lignes de code ci-dessus (ou similaire) sur mon programme, alors je m à la recherche d'une façon de le faire:

Private Sub setHandler(evt As Event, hndler As eventhandler) 
    RemoveHandler evt, hndler 
    AddHandler evt, hndler 
End Sub 

afin que partout où ces deux lignes de code (ou similaire) se produisent dans mon programme, je peux les remplacer par:

setHandler(combobox1.SelectedIndexChanged, AddressOf indexChangedHandler) 

jusqu'à présent , la partie "evt as Event" de la Le rgument de la fonction setHandler donne une erreur. P.S: J'ai posé cette question sur un ou deux autres forums et je continue de me demander pourquoi je voudrais régler le gestionnaire immédiatement après l'avoir retiré. La raison en est que l'ajout dynamique d'un gestionnaire d'événements n fois fait que le gestionnaire est exécuté n fois lorsque l'événement se produit. Pour éviter cela, c'est-à-dire, pour s'assurer que le gestionnaire est exécuté une seule fois lorsque l'événement se produit, je supprime d'abord le gestionnaire chaque fois que je souhaite ajouter dynamiquement le gestionnaire. Vous pourriez demander pourquoi le gestionnaire serait ajouté plusieurs fois en premier lieu ... La raison en est que j'ajoute le gestionnaire seulement après qu'un événement particulier, disons E1, soit survenu sous ma forme (j'ajoute le gestionnaire dans le gestionnaire de l'événement E1). Et l'événement E1 peut se produire plusieurs fois dans mon formulaire. Si je ne supprime pas le gestionnaire à chaque fois avant de l'ajouter à nouveau, le gestionnaire est ajouté et donc exécuté plusieurs fois. Quoi qu'il en soit, le traitement qui se produit au sein de la fonction n'est pour le moment pas très important pour moi, mais plutôt le moyen de passer un événement en paramètre.

+1

Pouvez-vous nous indiquer l'erreur? –

+0

Il n'y a pas de véritable moyen de le faire par programmation, car vous ne pouvez pas transmettre de références à un membre d'événement. Je ne sais pas exactement ce que setHandler est supposé faire ... pouvez-vous clarifier pourquoi vous devez supprimer un gestionnaire d'événements et l'ajouter à nouveau? – cdhowie

+0

@cdhowie J'étais en train d'éditer mon post pour expliquer pourquoi j'aurais besoin de faire cela, je me suis interrompu, je suis revenu et j'ai terminé le montage et soumis, avant de réaliser que vous avez déjà posé la question. Longue histoire courte, la raison est maintenant incluse dans l'article original :) – Tracer

Répondre

10

Bien sûr, vous pouvez passer des événements autour ... Eh bien, vous pouvez passer Action(Of EventHandler) qui peut faire ce que vous voulez.

Si vous avez une classe qui définit un événement comme ceci:

Public Class ComboBox 
    Public Event SelectedIndexChanged As EventHandler 
End Class 

Étant donné une instance de ComboBox vous pouvez créer ajouter & actions de gestionnaire remove comme ceci:

Dim combobox1 = New ComboBox() 

Dim ah As Action(Of EventHandler) 
    = Sub (h) AddHandler combobox1.SelectedIndexChanged, h 
Dim rh As Action(Of EventHandler) 
    = Sub (h) RemoveHandler combobox1.SelectedIndexChanged, h 

(Maintenant, c'est le code VB.NET 4.0, mais vous pouvez le faire en 3.5 en utilisant AddressOf et un peu plus de déblayage.)

Donc si je suis ve un gestionnaire Foo:

Public Sub Foo(ByVal sender as Object, ByVal e As EventArgs) 
    Console.WriteLine("Over here with Foo!") 
End Sub 

Et une méthode Raise sur ComboBox Je peux maintenant faire: "ici avec Foo"

ah(AddressOf Foo) 
combobox1.Raise() 
rh(AddressOf Foo) 

Ce écrit le message comme prévu.

Je peux aussi créer cette méthode:

Public Sub PassActionOfEventHandler(ByVal h As Action(Of EventHandler)) 
    h(AddressOf Foo) 
End Sub 

je peux passer autour des actions du gestionnaire d'événements comme ceci:

PassActionOfEventHandler(ah) 
combobox1.Raise() 
PassActionOfEventHandler(rh) 

qui écrit à nouveau le message "ici avec Foo!". Maintenant, un problème qui pourrait être un problème est que vous pouvez échanger accidentellement les délégués d'ajouter et de supprimer des gestionnaires d'événements dans le code - après tout, ils sont du même type. Il est donc facile de définir simplement les délégués fortement typées pour l'ajouter et supprimer des actions comme ceci:

Public Delegate Sub AddHandlerDelegate(Of T)(ByVal eh as T) 
Public Delegate Sub RemoveHandlerDelegate(Of T)(ByVal eh as T) 

Le code pour définir les instances de délégués ne change pas, sauf pour les types de délégués:

Dim ah As AddHandlerDelegate(Of EventHandler) 
    = Sub (h) AddHandler combobox1.SelectedIndexChanged, h 
Dim rh As RemoveHandlerDelegate(Of EventHandler) 
    = Sub (h) RemoveHandler combobox1.SelectedIndexChanged, h 

Cela vous permet maintenant d'être très créatif. Vous pouvez définir une fonction qui prendra le délégué du gestionnaire d'ajout, le délégué du gestionnaire de suppression et un gestionnaire d'événements, qui connectera un gestionnaire d'événements, puis vous retournera un IDisposable que vous pourrez utiliser plus tard pour supprimer le gestionnaire sans avoir besoin de Conservez une référence au gestionnaire d'événements. C'est pratique pour utiliser les instructions Using.

est ici la signature:

Function SubscribeToEventHandler(
    ByVal h as EventHandler, 
    ByVal ah As AddHandlerDelegate(Of EventHandler), 
    ByVal rh As RemoveHandlerDelegate(Of EventHandler)) As IDisposable 

Donc, étant donné cette fonction, je peux maintenant faire:

combobox1.Raise() 
Using subscription = SubscribeToEventHandler(AddressOf Foo, ah, rh) 
    combobox1.Raise() 
    combobox1.Raise() 
End Using 
combobox1.Raise() 

Et ce écrit le message "ici avec Foo!" seulement deux fois. Le premier et le dernier Raise appels sont en dehors de l'abonnement au gestionnaire d'événements.

Amusez-vous!

+1

Si je comprends bien, vous faites passer des 'Délégués ', pas les' Evénements 'eux-mêmes, comme demandé dans la question. Une très bonne réponse quand même. – Bobby

+0

Enigmativité, merci pour votre réponse détaillée. C'était un peu difficile à comprendre cependant, puisque j'ai vu des constructions étranges dans votre message (ma première fois de voir une telle syntaxe, alors s'il vous plaît nu avec moi). Mais d'après ce que j'ai compris, je dois toujours d'abord définir explicitement l'objet et l'événement dans "ah" et "rh", n'est-ce pas? ce que je voudrais savoir, c'est de ne pas limiter la définition de "ah" à "combobox1.selectedIndexChanged", de sorte que je puisse utiliser la même fonction pour définir le gestionnaire sur un objet différent (cbx2), disons " cbx2.selectedIndexChanged ". – Tracer

+0

@ 'Tracer' - Oui. Remplacez simplement les définitions de délégué par 'Public Delegate Sub AddHandlerDelegate (de T) (ByVal eh en tant que T, comboBox en tant que ComboBox)' et vous pouvez le faire fonctionner pour tout 'ComboBox'. Si vous devez faire d'autres événements, je suggère d'appeler le délégué 'AddSelectedIndexChangedHandler' etc. Un délégué d'ajout et de suppression pour chaque événement et chaque contrôle. – Enigmativity

2

Vous ne pouvez pas transmettre des événements. Event n'est pas un type, c'est un mot-clé qui définit une paire de méthodes, ajouter et supprimer, utilisée pour changer l'état du membre d'événement de la classe. Ils ressemblent beaucoup à des propriétés à cet égard (qui ont des méthodes get et set). Comme les propriétés, les méthodes add et remove peuvent faire ce que vous voulez. Généralement, ils ne font rien de plus que maintenir une instance de délégué, qui est elle-même MulticastDelegate ou, en d'autres termes, une liste de délégués qui sont appelés un par un si l'événement est déclenché.

Vous pouvez voir clairement cette structure en C#, où elle n'est pas masquée avec AddHandler/RemoveHandler, mais vous éditez directement la liste des gestionnaires associés: myObject.Event += new Delegate(...);. Et, comme les propriétés similaires, étant membre d'une classe qui abstrait deux méthodes différentes, il n'est pas possible de passer littéralement un événement en tant qu'objet.

+0

Merci pour cette explication, Bobby. – Tracer

2

Selon le contexte, le terme «événement» a différentes significations. Dans le contexte que vous recherchez, un événement est une paire de méthodes qui ajoutera ou supprimera un délégué d'une liste d'abonnement. Malheureusement, il n'y a pas de classe dans VB.NET pour représenter une adresse de méthode sans objet attaché.On pourrait probablement utiliser reflection pour aller chercher les méthodes appropriées, puis passer ces méthodes à une routine qui les appellerait toutes les deux, mais dans votre situation particulière, cela serait probablement stupide. La seule situation où je peux voir qu'il pourrait être utile de passer un événement dans le sens que vous décrivez serait pour quelque chose comme un objet IDisposable qui souscrit à des événements d'objets de plus longue durée, et qui a besoin de se désabonner tous ses événements quand il est disposé. Dans ce cas, il peut être utile d'utiliser la réflexion pour récupérer la méthode remove-delegate pour chaque événement, puis d'appeler toutes les méthodes remove-delegate lorsqu'un objet est supprimé. Malheureusement, je ne connais aucun moyen de représenter les événements à extraire sauf en tant que littéraux de chaînes, dont la validité ne peut être vérifiée avant l'exécution.

Questions connexes