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

Tra*_*cer 10 vb.net parameters events

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

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

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

RemoveHandler combobox1.SelectedIndexChanged, AddressOf indexChangedHandler
AddHandler combobox1.SelectedIndexChanged, AddressOf indexChangedHandler
Run Code Online (Sandbox Code Playgroud)

现在,我不想继续在我的程序中重复上面两行代码(或类似代码),所以我正在寻找一种方法来执行此操作:

Private Sub setHandler(evt As Event, hndler As eventhandler)
     RemoveHandler evt, hndler
     AddHandler evt, hndler
End Sub
Run Code Online (Sandbox Code Playgroud)

所以在我的程序中出现这两行代码(或类似代码)的地方,我可以用以下代码替换它们:

setHandler(combobox1.SelectedIndexChanged, AddressOf indexChangedHandler)
Run Code Online (Sandbox Code Playgroud)

到目前为止,setHandler函数参数的"evt as Event"部分给出了一个错误.

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

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

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

Eni*_*ity 12

当然你可以传递各种事件......你可以传递Action(Of EventHandler)哪些可以做你想要的.

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

Public Class ComboBox
    Public Event SelectedIndexChanged As EventHandler   
End Class
Run Code Online (Sandbox Code Playgroud)

给定一个实例,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
Run Code Online (Sandbox Code Playgroud)

(现在,这是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
Run Code Online (Sandbox Code Playgroud)

我现在可以这样做了一个Raise方法ComboBox:

ah(AddressOf Foo)
combobox1.Raise()
rh(AddressOf Foo)
Run Code Online (Sandbox Code Playgroud)

这会写消息"Over here with Foo!" 正如所料.

我也可以创建这个方法:

Public Sub PassActionOfEventHandler(ByVal h As Action(Of EventHandler))
    h(AddressOf Foo)
End Sub
Run Code Online (Sandbox Code Playgroud)

我可以传递事件处理程序操作,如下所示:

PassActionOfEventHandler(ah)
combobox1.Raise()
PassActionOfEventHandler(rh)
Run Code Online (Sandbox Code Playgroud)

这又写了一条消息"Over here with Foo!".

现在,一个可能存在问题的问题是您可能会意外地在代码中交换添加和删除事件处理程序委托 - 毕竟它们是相同的类型.因此,很容易为添加和删除操作定义强类型委​​托,如下所示:

Public Delegate Sub AddHandlerDelegate(Of T)(ByVal eh as T)
Public Delegate Sub RemoveHandlerDelegate(Of T)(ByVal eh as T)
Run Code Online (Sandbox Code Playgroud)

除委托类型外,定义委托实例的代码不会更改:

Dim ah As AddHandlerDelegate(Of EventHandler)
    = Sub (h) AddHandler combobox1.SelectedIndexChanged, h
Dim rh As RemoveHandlerDelegate(Of EventHandler)
    = Sub (h) RemoveHandler combobox1.SelectedIndexChanged, h
Run Code Online (Sandbox Code Playgroud)

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

这是签名:

Function SubscribeToEventHandler(
    ByVal h as EventHandler,
    ByVal ah As AddHandlerDelegate(Of EventHandler),
    ByVal rh As RemoveHandlerDelegate(Of EventHandler)) As IDisposable
Run Code Online (Sandbox Code Playgroud)

所以有了这个功能,我现在可以这样做:

combobox1.Raise()
Using subscription = SubscribeToEventHandler(AddressOf Foo, ah, rh)
    combobox1.Raise()
    combobox1.Raise()
End Using
combobox1.Raise()
Run Code Online (Sandbox Code Playgroud)

这写了一条消息"Over here with Foo!" 只有两次.第一个和最后一个Raise调用不在对事件处理程序的订阅之外.

请享用!