简体   繁体   中英

AddressOf in Visual Basic .NET

I have buttons generated through code (dynamically). I have to associate an event (the same) to them. I use AddHandler button.click, AddressOf mysub .

The issue is that mysub gets a string ( mysub(string )), but AddressOf doesn't accept a parameter inside the routine. How can I do this? Using also an alternative to AddressOf.

Public Class Form1

   ...

   Private Sub mysub(ByVal sender As Object, ByVal e As System.EventArgs, ByVal str As String)
      ...
      ...
   End Sub

   ...

   Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

      ...

      While something
         ...
         Dim btn As New Button
         ...
         AddHandler btn.click, AddressOf mysub 'here the issue
      End While

      ...

   End Sub
End Class

It sounds like you have the following scenario

Class MyClass
  Public button As Button

  Public Sub New() 
    AddHandler button.Click AddressOf MySub
  End Sub

  Public Sub MySub(p As String)

  End Sub

End Class

If that's the case then you have a couple of options. The simplest is to use a helper method. Have it be the event handler and then call the MySub function

  Public Sub New() 
    AddHandler button.Click AddressOf MyHelper
  End Sub

  Public Sub MyHelper(sender As Object, e As EventArgs)
    MySub(TheStringValue)
  End Sub

EDIT

After talking with OP the problem is passing a local from the Form1_Load function into the MySub method. If you're using Visual Studio 2010 the easiest way to do this is with a Sub lambda expression

Dim theString = ...
AddHandler button.Click (Sub (sender, e) MySub(sender, e))

If your using an earlier version of Visual Studio it's a bit harder because you need to manually build up a closure.

Class Closure 
  Public TheForm as Form1
  Public TheString As String
  Public Sub OnClick(sender As Object, e As EventArgs)
    TheForm.MySub(sender, e)
  End Sub
End Class

...

' In Form1_Load
Dim closure As New Closure
closure.TheForm = Me
closure.TehString = get the string 

AddHandler button.Click AddressOf closure.OnClick

I think there is a misunderstanding about what AddressOf really does and really is.

AddressOf is simply storing a MEMORY ADDRESS to a function or method called . Read about .NET Delegates and you will get the concept but the key is to understand that a delegate is: a type in .NET to store MEMORY ADDRESSES of methods. Just that. Does a delegate variable store any method? No, not any method, only the methods whose signature matches the declaration of the Delegate.

And then you should learn about the concept of Events, which is very attached to the Delegates simply because an Event needs to know what delegate will handle it (who is the eventHandler, which is a delegate)

Now you mentioned something of being unable to pass arguments to the AddressOf. This is your misunderstanding. You don't pass any arguments to AddressOf because you pass directly a memory address to a method or function, and that method or function will contain already the arguments as per its declaration.

So when you find something like:

AddHandler button.click, AddressOf mysub

what you are telling to the compiler is: "I know that the Button called button has the ability to trigger events when clicked on it. So I want to handle (delegate the action that happens) this click event with the method mysub wherever it is living in memory.."

mysub is the method that it will be executed when the button is clicked.

You were wondering what arguments to pass or how to pass arguments. YOU DON'T pass any arguments because it will be the button click event who will pass these arguments. You can just handle the parameters that the method mysub receives from the button.

And how do you know what parameters mysub should receive from the button? Because they MUST be the ones defined in the Delegate definition. Remember that we said that delegate variables don't store memory addresses to any method but only to methods whose signature matches the definition of the delegate attached to the button event click

So go to the definition of the Button event and you will find that it is using a delegate type. Have a look at the signature of that delegate and you will know exactly what are the type of arguments that the methods this delegate store have.

However the good practices say that the Events should be attached to Delegates whose signature (the method's signature it can store) contains 2 arguments:

  • First argument is the sender, the object that generated the event. So it is a

    sender as Object
  • Second argument is an object that wraps any other parameter with more information, the object must be a EventArgs (or inherit it)

     e as EventArgs

As a specific answer. If you want an alternative to pass the memory address of a method that will handle the click event of your button, simply don't pass any memory address and have the content of a function like:

AddHandler button.click, Sub (ByVal sender As Object, ByVal e As System.EventArgs, ByVal str As String)
  'do something here
   End Sub

so in this case you would say to the compiler: "when the Button named button generates a click event I want you to execute this anonymous (it has no name) method. And as I know that the button's click event passes 2 arguments, please put the first argument in my sender variable and the second argument in my EventArgs variable"

The AddHandler operator does not call the handler so it doesn't make sense to try to pass it a variable during that command. AddHandler just tells the framework that the mysub method needs to be called whenever the event is raised.

UPDATE You should look into the Button.CommandArgument property. This will allow you to assign an arbitrary value to your button that will be accessible in your event handler. Since the property belongs to the button, this will only help if the value you want to pass will not change for each button. In other words, if every time you press button1 , you want to pass in foo , this will work. Otherwise, it wont be helpful.

In Form.Load:

btn.CommandArgument = "foo";

In your handler:

Button btn = (Button)sender;
Console.Write(btn.CommandArgument); //foo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM