Reputation: 42260
I have some code where I need to dynamically bind events to an event handler:
foreach (string evnt in attribute.Events)
{
EventInfo ei = control.GetType().GetEvent(evnt);
if(ei != null)
{
ei.AddEventHandler(control, new EventHandler((s, e) =>
{
// More awesomeness here...
}));
}
}
So for each string in the event list, get the event from the control and bind a handler.
The problem is that not all events are EventHandler
, some for example might be KeyEventHander
or MouseEventHandler
etc.
I don't want a massive if/else list of EventHandler
derived types, I just want to bind the same handler regardless of what type of EventHandler
it is.
How can I do this?
Upvotes: 3
Views: 1118
Reputation: 2323
You can use dynamic key word to attach the handler. More explanation you can find here: https://msdn.microsoft.com/en-us/library/ms228976(v=vs.110).aspx
Upvotes: 0
Reputation: 27861
Here is one way to do it:
First create this helper class:
public class HandlerHelper<T> where T : EventArgs
{
private readonly EventHandler m_HandlerToCall;
public HandlerHelper(EventHandler handler_to_call)
{
m_HandlerToCall = handler_to_call;
}
public void Handle(object sender, T args)
{
m_HandlerToCall.Invoke(sender, args);
}
}
This generic class has a Handle
method that will be used to be our delegate for the many event handler types. Note that this class is generic. T
will be one of the many EventArgs
derived classes for different event types.
Now let's say you define the following event handler:
var event_handler = new EventHandler((s, args) =>
{
// More awesomeness here...
});
Here is how you can use the helper class to create different delegates for the different event handler types that will invoke event_handler
:
foreach (var event_name in event_names)
{
var event_info = control.GetType().GetEvent(event_name);
var event_handler_type = event_info.EventHandlerType;
var event_args_type = event_handler_type.GetMethod("Invoke").GetParameters()[1].ParameterType;
var helper_type = typeof(HandlerHelper<>).MakeGenericType(event_args_type);
var helper = Activator.CreateInstance(helper_type, event_handler);
Delegate my_delegate = Delegate.CreateDelegate(event_handler_type, helper, "Handle");
event_info.AddEventHandler(button, my_delegate);
}
For each event, we obtain the EventHandlerType
which is like EventHandler
or MouseEventHandler
.
Then we use reflection to get the type of the second parameter which is like EventArgs
or MouseEventArgs
.
Then we create an instance of HandlerHelper<>
based on the type of the EventArgs
parameter. For example HandlerHelper<EventArgs>
or HandlerHelper<MouseEventArgs>
.
We give event_handler
to the constructor of HandlerHelper
so that it can call it when it's Handle
method is invoked.
This makes the signature of the Handle
method as we want. For example, in the case of HandlerHelper<MouseEventArgs>
, the signature of the Handle
method is:
void Handle(object sender, MouseEventArgs args)
Now, we use Delegate.CreateDelegate
to create a delegate based on the Handle
method for the specific HandlerHelper
object that we created, and we give such delegate to the AddEventHandler
method.
For performance reasons, you can cache the delegate (instead of creating one every time) based on event_args_type
.
Upvotes: 3