I need to pass an event as a parameter to a function. Is there a way of doing this?
The reason is that I have a sequence of two lines of code that is littered all over my program, where I dynamically remove the handler to an event, and then set the handler again. I'm doing this for several different events and event handlers, so I've decided to write a function that does this.
As an example, let's say I have a combobox in my code called combobox1, and I have the handler called indexChangedHandler. In several places of my code, I have the following two lines:
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
setHandler(combobox1.SelectedIndexChanged, AddressOf indexChangedHandler)
Of course you can pass events around... Well you can pass
Action(Of EventHandler) which can do what you want.
If you have a class that defines an event like so:
Public Class ComboBox Public Event SelectedIndexChanged As EventHandler End Class
Given an instance of
ComboBox you can then create add & remove handler actions like so:
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
(Now, this is VB.NET 4.0 code, but you can do this in 3.5 using
AddressOf and a little more mucking about.)
So if I have a handler
Public Sub Foo(ByVal sender as Object, ByVal e As EventArgs) Console.WriteLine("Over here with Foo!") End Sub
Raise method on
ComboBox I can now do this:
ah(AddressOf Foo) combobox1.Raise() rh(AddressOf Foo)
This writes the message "Over here with Foo!" as expected.
I can also create this method:
Public Sub PassActionOfEventHandler(ByVal h As Action(Of EventHandler)) h(AddressOf Foo) End Sub
I can pass around the event handler actions like so:
PassActionOfEventHandler(ah) combobox1.Raise() PassActionOfEventHandler(rh)
Which again writes the message "Over here with Foo!".
Now, one issue that might be a problem is that you can accidentally swap the add and remove event handler delegates in code - after all they are the same type. So it is easy to just define strongly-typed delegates for the add and remove actions like so:
Public Delegate Sub AddHandlerDelegate(Of T)(ByVal eh as T) Public Delegate Sub RemoveHandlerDelegate(Of T)(ByVal eh as T)
The code to define the delegate instances doesn't change except for the delegate types:
Dim ah As AddHandlerDelegate(Of EventHandler) = Sub (h) AddHandler combobox1.SelectedIndexChanged, h Dim rh As RemoveHandlerDelegate(Of EventHandler) = Sub (h) RemoveHandler combobox1.SelectedIndexChanged, h
So this now lets you be very creative. You can define a function that will take the add handler delegate, the remove handler delegate and a event handler, which will wire-up an event handler, and then return to you an
IDisposable that you can use later to remove the handler without needing to retain a reference to the event handler. This is handy for using
Here's the signature:
Function SubscribeToEventHandler( ByVal h as EventHandler, ByVal ah As AddHandlerDelegate(Of EventHandler), ByVal rh As RemoveHandlerDelegate(Of EventHandler)) As IDisposable
So given this function I can now do this:
combobox1.Raise() Using subscription = SubscribeToEventHandler(AddressOf Foo, ah, rh) combobox1.Raise() combobox1.Raise() End Using combobox1.Raise()
And this writes the message "Over here with Foo!" only twice. The first and last
Raise calls are outside of the subscription to the event handler.