1

我有通过代码(动态)生成的按钮。我必须将一个事件(相同的)与他们联系起来。我用AddHandler button.click, AddressOf mysub.

问题是 mysub 得到一个字符串 ( mysub(string)),但 AddressOf 不接受例程内的参数。我怎样才能做到这一点?也使用 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
4

3 回答 3

6

听起来您有以下情况

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

如果是这种情况,那么您有几个选择。最简单的是使用辅助方法。让它成为事件处理程序,然后调用MySub函数

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

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

编辑

在与 OP 交谈后,问题是将Form1_Load函数中的局部变量传递给MySub方法。如果您使用的是 Visual Studio 2010,最简单的方法是使用Sublambda 表达式

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

如果您使用的是早期版本的 Visual Studio,这会有点困难,因为您需要手动构建一个闭包。

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 闭包.OnClick

于 2011-08-18T18:28:08.303 回答
0

操作员不会调用处理程序,因此在该AddHandler命令期间尝试将变量传递给它是没有意义的。AddHandler只是告诉框架mysub无论何时引发事件都需要调用该方法。

更新 您应该查看Button.CommandArgument属性。这将允许您为您的按钮分配一个任意值,该值可在您的事件处理程序中访问。由于该属性属于按钮,因此只有在您要传递的值不会为每个按钮更改时,这才会有所帮助。换句话说,如果你每次按button1,你都想传入foo,这将起作用。否则,它不会有帮助。

在 Form.Load 中:

btn.CommandArgument = "foo";

在您的处理程序中:

Button btn = (Button)sender;
Console.Write(btn.CommandArgument); //foo
于 2011-08-18T18:33:05.713 回答
0

我认为对于 AddressOf 的真正作用和实际情况存在误解。

AddressOf 只是将 MEMORY ADDRESS 存储到调用的函数或方法中。阅读 .NET 委托,您将了解这个概念,但关键是要了解委托是:.NET 中的一种类型,用于存储方法的内存地址。只是。委托变量是否存储任何方法?不,不是任何方法,只有签名与委托声明匹配的方法。

然后你应该了解Events的概念,它非常依赖于Delegates,仅仅是因为Event需要知道什么委托将处理它(谁是eventHandler,它是一个委托)

现在您提到了无法将参数传递给 AddressOf 的问题。这是你的误解。您不向 AddressOf 传递任何参数,因为您直接将内存地址传递给方法或函数,并且该方法或函数将根据其声明已经包含参数。

所以当你找到类似的东西时:

AddHandler button.click, AddressOf mysub

您要告诉编译器的是:“我知道名为 button 的按钮能够在单击它时触发事件。所以我想用 mysub 方法处理(委托发生的操作)这个单击事件,无论它在哪里活在记忆里……”

mysub 是单击按钮时将执行的方法。

您想知道要传递哪些参数或如何传递参数。您不要传递任何参数,因为传递这些参数的将是按钮单击事件。您可以只处理 mysub 方法从按钮接收的参数。

你怎么知道 mysub 应该从按钮接收哪些参数?因为它们必须是 Delegate 定义中定义的那些。请记住,我们说过委托变量不会将内存地址存储到任何方法,而只会存储其签名与附加到按钮事件单击的委托的定义相匹配的方法

所以转到Button事件的定义,你会发现它使用的是委托类型。查看该委托的签名,您将确切知道该委托存储的方法具有哪些参数类型。

然而,良好实践表明事件应该附加到其签名(它可以存储的方法的签名)包含 2 个参数的委托上:

  • 第一个参数是发送者,即生成事件的对象。所以它是一个

    sender as Object
    
  • 第二个参数是一个包含更多信息的任何其他参数的对象,该对象必须是 EventArgs(或继承它)

    e as EventArgs
    

作为一个具体的答案。如果您想要一种替代方法来传递将处理按钮的单击事件的方法的内存地址,只需不要传递任何内存地址并具有如下函数的内容:

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

所以在这种情况下,你会对编译器说:“当名为按钮的按钮生成点击事件时,我希望你执行这个匿名(它没有名称)方法。而且我知道按钮的点击事件传递了 2 个参数,请将第一个参数放在我的 sender 变量中,将第二个参数放在我的 EventArgs 变量中”

于 2014-08-12T00:02:30.380 回答