Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VB.NET: "AddHandler" by specifying Handler function as a variable

I'm writing an add-in for Autodesk Inventor (a 3D CAD program). The add-in adds a bunch of internal commands to Inventor, and creates a toolbar button for each command. I need to connect the Execute event for each of those commands to a handler function in my add-in.

I've created a "MyCommand" class, which contains all of the information necessary to define the command. I've also created a List(Of MyCommand) with the definitions for each command. Finally, I can iterate through each command and create the internal Inventor command definition, as well as add the button to the toolbar. However, what I can't figure out how to do is associate the command with its Handler function within the loop.

The example code below illustrates what I'm after:

Sub CreateCommands()
    Dim oCommands As New List(Of MyCommand)

    oCommands.Add(New MyCommand("DrawLogoCmd", "Draw Logo", "DrawLogoSub"))
    oCommands.Add(New MyCommand("PublishDrawingCmd", "Publish Drawing", "PublishDrawingSub"))
    ' [Dozens more commands]

    For Each oCommand As MyCommand In oCommands
        ' Code for adding internal command definition and button to Inventor. This is working fine.
        Dim oCommandDef As Inventor.CommandDefinition = InventorApp.CommandDefinitions.Add(oCommand.InternalDefinitionName, oCommand.DisplayName)
        InventorApp.ToolbarButtons.Add(oCommandDef)

        ' Associate command definition with handler function
        ' ===== THIS IS THE LINE I NEED TO FIGURE OUT =====
        AddHandler oCommandDef.OnExecute, AddressOf oCommand.HandlerSubName
    Next
End Sub

Sub DrawLogoSub()
    ' [My add-in's code to draw logo in Inventor]
End Sub

Sub PublishDrawingSub()
    ' [My add-in's code to publish drawing in Inventor]
End Sub

Class MyCommand
    Public InternalDefinitionName As String
    Public DisplayName As String
    Public HandlerSubName As String

    Sub New(InternalDefinitionName As String, DisplayName As String, HandlerSubName As String)
        With Me
            .InternalDefinitionName = InternalDefinitionName
            .DisplayName = DisplayName
            .HandlerSubName = HandlerSubName
        End With
    End Sub
End Class

So, is this possible? Is there some way to get the "AddressOf" my function using its name as a string? Or, is there some way to store a reference to the function itself in my MyCommand class, and pass that to the AddressOf operator?

Or, is there some other way besides "AddHandler/AddressOf" that might work?

Any suggestions are appreciated.

like image 891
DRoam Avatar asked Aug 15 '26 02:08

DRoam


1 Answers

Yes, you could find the method by name using reflection, but I wouldn't recommend it. The AddHandler command is usually given the AddressOf a method, but it can also take a delegate, as long as it conforms to the event's signature. So, unless you have some need to do it by string, I would recommend doing something like this instead. Assuming that the event matches the normal EventHandler delegate:

Sub CreateCommands()
    Dim oCommands As New List(Of MyCommand)

    oCommands.Add(New MyCommand("DrawLogoCmd", "Draw Logo", AddressOf DrawLogo))
    oCommands.Add(New MyCommand("PublishDrawingCmd", "Publish Drawing", AddressOf PublishDrawing))
    ' [Dozens more commands]

    For Each oCommand As MyCommand In oCommands
        ' Code for adding internal command definition and button to Inventor. This is working fine.
        Dim oCommandDef As Inventor.CommandDefinition = InventorApp.CommandDefinitions.Add(oCommand.InternalDefinitionName, oCommand.DisplayName)
        InventorApp.ToolbarButtons.Add(oCommandDef)

        ' Associate command definition with handler function
        AddHandler oCommandDef.OnExecute, oCommand.Handler
    Next
End Sub

Sub DrawLogo(sender As Object, e As EventArgs)
    ' [My add-in's code to draw logo in Inventor]
End Sub

Sub PublishDrawing(sender As Object, e As EventArgs)
    ' [My add-in's code to publish drawing in Inventor]
End Sub

Class MyCommand
    Public InternalDefinitionName As String
    Public DisplayName As String
    Public Handler As EventHandler

    Sub New(InternalDefinitionName As String, DisplayName As String, Handler As EventHandler)
        With Me
            .InternalDefinitionName = InternalDefinitionName
            .DisplayName = DisplayName
            .Handler = Handler
        End With
    End Sub
End Class

If you really need to do it by string, you could use reflection like this (note that I used NameOf rather than hard-coding the method names as string literals, just to make it safer):

Sub CreateCommands()
    Dim oCommands As New List(Of MyCommand)

    oCommands.Add(New MyCommand("DrawLogoCmd", "Draw Logo", NameOf(DrawLogo)))
    oCommands.Add(New MyCommand("PublishDrawingCmd", "Publish Drawing", NameOf(PublishDrawing)))
    ' [Dozens more commands]

    For Each oCommand As MyCommand In oCommands
        ' Code for adding internal command definition and button to Inventor. This is working fine.
        Dim oCommandDef As Inventor.CommandDefinition = InventorApp.CommandDefinitions.Add(oCommand.InternalDefinitionName, oCommand.DisplayName)
        InventorApp.ToolbarButtons.Add(oCommandDef)

        ' Associate command definition with handler function
        AddHandler oCommandDef.OnExecute, Sub(sender As Object, e As EventArgs) CallMethod(oCommand.Handler)
    Next
End Sub

Private Sub CallMethod(name As String)
    Me.GetType().GetMethod(name).Invoke(Me, Nothing)
End Sub

Sub DrawLogo()
    ' [My add-in's code to draw logo in Inventor]
End Sub

Sub PublishDrawing()
    ' [My add-in's code to publish drawing in Inventor]
End Sub
like image 105
Steven Doggart Avatar answered Aug 16 '26 23:08

Steven Doggart



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!