我有一些代码需要将事件动态绑定到事件处理程序:
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...
}));
}
}
因此,对于事件列表中的每个字符串,请从控件中获取事件并绑定处理程序.
问题在于,并非所有事件都是EventHandler,例如某些事件可能是KeyEventHander或MouseEventHandler等.
我不希望有大量的EventHandler派生类型的if / else列表,我只想绑定相同的处理程序,而不管它是什么类型的EventHandler.
我怎样才能做到这一点?
解决方法:
这是一种实现方法:
首先创建此帮助程序类:
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);
}
}
这个通用类具有一个Handle方法,该方法将用作许多事件处理程序类型的委托.请注意,此类是通用的. T将是针对不同事件类型的许多EventArgs派生类之一.
现在,假设您定义了以下事件处理程序:
var event_handler = new EventHandler((s, args) =>
{
// More awesomeness here...
});
这是如何使用帮助程序类为将调用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);
}
对于每个事件,我们都获得类似于EventHandler或MouseEventHandler的EventHandlerType.
然后,我们使用反射来获取第二个参数的类型,例如EventArgs或MouseEventArgs.
然后,我们创建HandlerHelper<>的实例.基于EventArgs参数的类型.例如,HandlerHelper< EventArgs>或HandlerHelper< MouseEventArgs>.
我们将event_handler提供给HandlerHelper的构造函数,以便它在调用Handle方法时可以调用它.
这样就可以根据需要对Handle方法进行签名.例如,在HandlerHelper< MouseEventArgs>的情况下,Handle方法的签名为:
void Handle(object sender, MouseEventArgs args)
现在,我们使用Delegate.CreateDelegate为创建的特定HandlerHelper对象基于Handle方法创建一个委托,并将该委托提供给AddEventHandler方法.
出于性能原因,您可以基于event_args_type缓存委托(而不是每次创建委托).