2010-03-10 3 views
3

Ceci est probablement un simple mais je n'arrive pas à le comprendre.InvokeMember à l'aide de GetField. Champ non trouvé dans VB.NET

J'ai un tas d'éléments de formulaire créés par le concepteur de forme déclarée (en frmAquRun.Designer.vb)

Public WithEvents btnAquRunEvent1 As VisibiltyButtonLib.VisibilityButton 
Public WithEvents btnAquRunEvent2 As VisibiltyButtonLib.VisibilityButton 

... etc

Et je veux essentiellement être en mesure de fournir un nombre à une fonction accède à chacun de ces champs. J'ai donc écrit cette fonction. (en frmAquRun.vb)

Const EVENT_BUTTON_PREFIX As String = "btnAquRunEvent" 
Public Function getEventButton(ByVal id As Integer) As Windows.Forms.Button 

    Dim returnButton As Windows.Forms.Button = Nothing 
    Try 
     returnButton = DirectCast(Me.GetType().InvokeMember(eventButtonName, Reflection.BindingFlags.GetField Or Reflection.BindingFlags.Public Or Reflection.BindingFlags.Instance, Nothing, Me, Nothing), Windows.Forms.Button) 
    Catch ex As Exception 
    End Try 
    Return returnButton 
End Function 

Mais il semble toujours générer des exceptions de champ non trouvées. Le message de l'exception est "Champ" ATSIS_ControlProgram.frmAquRun.btnAquRunEvent1 "introuvable.".

L'espace de noms et le nom de formulaire dans le message sont corrects. Une idée de ce que je fais mal?

Répondre

3

Le problème est que pour les champs WithEvents, VB crée réellement une propriété qui attache et détache le gestionnaire d'événements nécessaire. La propriété générée porte le nom du champ. Le champ de sauvegarde réel est renommé _ + nom d'origine. 1)

Alors pour que votre code fonctionne préfixe simplement le nom du bouton par _ ou utilisez le BindingFlag qui correspond au getter de la propriété (au lieu de GetField).

Vous pouvez faire beaucoup plus facile en utilisant la collection Controls de la forme:

returnButton = DirectCast(Me.Controls(eventButtonName), Windows.Forms.Button) 

Mais méfiez-vous que cela ne fonctionne que si le bouton est de haut niveau, à savoir non imbriqué dans un contrôle conteneur Sur le formulaire.


1) C'est un détail d'implémentation du compilateur VB, mais il est portable (en particulier au compilateur Mono vbnc) depuis la manipulation des WithEvents champs est décrit en détail dans les spécifications du langage VB.

+0

Merci, en définissant le bindingFlags à GetProperty a fait l'affaire. Je ne connaissais pas l'objet Contrôles dans le formulaire Je le garderai à l'esprit pour référence future, mais les boutons d'événements sont dans des conteneurs différents, ce qui rendrait les choses un peu compliquées. – Isaiah

0

Le problème est que les gestionnaires d'événements ne sont pas vraiment des champs. Comme compilé, ce sont vraiment des propriétés qui implémentent les méthodes add_btnAquRunEventX, remove_btnAquRunEventX et fire_btnAquRunEventX. Il y a des façons d'utiliser la réflexion pour contourner cela, mais ce n'est probablement pas la meilleure façon d'aborder le problème. Au lieu de cela, vous pouvez simplement créer une liste <> et la remplir avec les gestionnaires d'événements, puis indexer dans cette liste.

Je suis un peu rouillé dans la syntaxe VB, mais il devrait ressembler à ceci:

Dim events = New List<EventHandler>() 
events.Add(btnAquRunEvent1) 
events.Add(btnAquRunEvent2) 

.... 

events(0)(null, EventArgs.Empty) 

Prenez un pas en arrière si et pourquoi vous évaluer l'invocation par index. Il peut y avoir une façon plus simple d'abstraire tout ce qui n'implique pas toute cette indirection.

+0

Votre description des gestionnaires d'événements est correcte, mais l'OP ne demandait pas * sur les gestionnaires d'événements, mais plutôt sur les champs 'WithEvent'. –

+0

Merci, j'utilisais auparavant une méthode comme vous l'avez décrit ci-dessus mais je voulais avoir une manière d'ajouter/supprimer des boutons du concepteur (comme cela peut dans certains cas être édité par des gens qui sont pas les concepteurs de logiciels.) – Isaiah

+0

Eh bien, cela ne fait que souligner ma sagesse VB. Je pensais que la syntaxe WithEvents était fondamentalement la même chose que le mot clé d'événement de C#. –