简体   繁体   English

使用反射将事件处理程序绑定到任何类型的事件

[英]Binding an event handler to any type of event using reflection

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. 问题是并非所有事件都是EventHandler ,例如某些EventHandler可能是KeyEventHanderMouseEventHandler等。

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. 我不想要一个大量的if / else列表的EventHandler派生类型,我只想绑定相同的处理程序,无论它是什么类型的EventHandler

How can I do this? 我怎样才能做到这一点?

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. 这个泛型类有一个Handle方法,它将用作许多事件处理程序类型的委托。 Note that this class is generic. 请注意,此类是通用的。 T will be one of the many EventArgs derived classes for different event types. T将是针对不同事件类型的许多EventArgs派生类之一。

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 : 以下是如何使用helper类为将调用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 . 对于每个事件,我们获取EventHandlerType ,它类似于EventHandlerMouseEventHandler

Then we use reflection to get the type of the second parameter which is like EventArgs or MouseEventArgs . 然后我们使用反射来获取第二个参数的类型,如EventArgsMouseEventArgs

Then we create an instance of HandlerHelper<> based on the type of the EventArgs parameter. 然后我们根据EventArgs参数的类型创建一个HandlerHelper<>实例。 For example HandlerHelper<EventArgs> or HandlerHelper<MouseEventArgs> . 例如HandlerHelper<EventArgs>HandlerHelper<MouseEventArgs>

We give event_handler to the constructor of HandlerHelper so that it can call it when it's Handle method is invoked. 我们给event_handler到的构造HandlerHelper ,以便它可以调用它时,它的Handle方法被调用。

This makes the signature of the Handle method as we want. 这使得Handle方法的签名成为我们想要的。 For example, in the case of HandlerHelper<MouseEventArgs> , the signature of the Handle method is: 例如,在HandlerHelper<MouseEventArgs>的情况下, Handle方法的签名是:

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. 现在,我们使用Delegate.CreateDelegate基于我们创建的特定HandlerHelper对象的Handle方法创建委托,并将这样的委托给予AddEventHandler方法。

For performance reasons, you can cache the delegate (instead of creating one every time) based on event_args_type . 出于性能原因,您可以基于event_args_type缓存委托(而不是每次创建一个委托)。

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 您可以在此处找到更多解释: https//msdn.microsoft.com/en-us/library/ms228976(v = vs.110).aspx

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM