VB.NET - 将事件作为参数传递

标签 vb.net events parameters

我需要将事件作为参数传递给函数。有没有办法做到这一点?

原因是我的程序中有两行代码序列,其中我动态地将处理程序删除到事件,然后再次设置处理程序。我正在为几个不同的事件和事件处理程序执行此操作,因此我决定编写一个执行此操作的函数。

例如,假设我的代码中有一个名为 combobox1 的组合框,并且我有一个名为 indexChangedHandler 的处理程序。在我的代码的几个地方,我有以下两行:

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

现在,我不想在我的程序中继续重复上述两行代码(或类似代码),所以我正在寻找一种方法来做到这一点:
Private Sub setHandler(evt As Event, hndler As eventhandler)
     RemoveHandler evt, hndler
     AddHandler evt, hndler
End Sub

因此,在我的程序中出现这两行代码(或类似代码)的任何地方,我都可以将它们替换为:
setHandler(combobox1.SelectedIndexChanged, AddressOf indexChangedHandler)

到目前为止,setHandler 函数的参数的“evt as Event”部分给出了错误。

P.S:我在其他几个论坛上问过这个问题,并一直被问到为什么我要在删除处理程序后立即设置它。原因是因为动态添加事件处理程序 n 次会导致该处理程序在事件发生时执行 n 次。为了避免这种情况,即为了确保事件发生时处理程序只执行一次,我每次要动态添加处理程序时首先删除处理程序。

您可能会问为什么首先要多次添加处理程序...原因是因为我仅在我的表单中发生特定事件(例如 E1)之后添加处理程序(我在处理程序中添加处理程序事件 E1)。并且事件 E1 可以在我的表单中发生多次。如果我在再次添加之前每次都没有删除处理程序,则处理程序会被添加并因此执行多次。

无论如何,此时函数内发生的处理对我来说并不是最重要的,而只是将事件作为参数传递的手段。

最佳答案

当然你可以传递事件...好吧你可以传递Action(Of EventHandler)这可以做你想做的事。

如果您有一个定义如下事件的类:

Public Class ComboBox
    Public Event SelectedIndexChanged As EventHandler   
End Class

给定 ComboBox 的实例然后,您可以像这样创建添加和删除处理程序操作:
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

(现在,这是 VB.NET 4.0 代码,但您可以在 3.5 中使用 AddressOf 来执行此操作,并且稍微麻烦一点。)

所以如果我有一个处理程序 Foo :
Public Sub Foo(ByVal sender as Object, ByVal e As EventArgs)
    Console.WriteLine("Over here with Foo!")
End Sub

还有一个 Raise ComboBox上的方法我现在可以这样做:
ah(AddressOf Foo)
combobox1.Raise()
rh(AddressOf Foo)

这会写出消息“和 Foo 一起过来!”正如预期的那样。

我也可以创建这个方法:
Public Sub PassActionOfEventHandler(ByVal h As Action(Of EventHandler))
    h(AddressOf Foo)
End Sub

我可以像这样传递事件处理程序操作:
PassActionOfEventHandler(ah)
combobox1.Raise()
PassActionOfEventHandler(rh)

它再次写出消息“和Foo一起过来!”。

现在,一个可能成为问题的问题是,您可能会意外地在代码中交换添加和删除事件处理程序委托(delegate)——毕竟它们是相同的类型。因此很容易为添加和删除操作定义强类型委​​托,如下所示:
Public Delegate Sub AddHandlerDelegate(Of T)(ByVal eh as T)
Public Delegate Sub RemoveHandlerDelegate(Of T)(ByVal eh as T)

除了委托(delegate)类型之外,定义委托(delegate)实例的代码不会改变:
Dim ah As AddHandlerDelegate(Of EventHandler)
    = Sub (h) AddHandler combobox1.SelectedIndexChanged, h
Dim rh As RemoveHandlerDelegate(Of EventHandler)
    = Sub (h) RemoveHandler combobox1.SelectedIndexChanged, h

所以现在这让你很有创意。您可以定义一个函数,该函数将接受添加处理程序委托(delegate)、删除处理程序委托(delegate)和一个事件处理程序,它将连接一个事件处理程序,然后返回给您一个 IDisposable您可以稍后使用它来删除处理程序,而无需保留对事件处理程序的引用。这对于使用 Using 很方便陈述。

这是签名:
Function SubscribeToEventHandler(
    ByVal h as EventHandler,
    ByVal ah As AddHandlerDelegate(Of EventHandler),
    ByVal rh As RemoveHandlerDelegate(Of EventHandler)) As IDisposable

所以有了这个功能,我现在可以这样做:
combobox1.Raise()
Using subscription = SubscribeToEventHandler(AddressOf Foo, ah, rh)
    combobox1.Raise()
    combobox1.Raise()
End Using
combobox1.Raise()

这会写出消息“和Foo一起过来!”只有两次。第一个和最后一个Raise调用在事件处理程序的订阅之外。

享受!

关于VB.NET - 将事件作为参数传递,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4142728/

相关文章:

.net - VB.NET 防止按钮获得焦点

.net - 来自外部 dll 的数据类型问题

c# - 派生类应该处理基类的事件吗? (C#/WPF)

c# - 如何将鼠标单击方法作为参数传递?

javascript - 函数参数...函数检查(对象){}

javascript - 单引号参数与无引号参数?

vb.net - 从 INI 文件读取

vb.net - “最佳”差异算法

java - 如何知道哪个 JCheckBox 发送了 ItemEvent

events - 为什么我第一次无法更改 mxEvent.CHANGE 事件中的样式?