我试图通过反射获取按钮的Click事件,这是我的代码:
Assembly assem = Assembly.GetExecutingAssembly();
Type tExForm = btnSave.GetType();
Object exFormAsObj = Activator.CreateInstance(tExForm);
EventInfo evClick = tExForm.GetEvent("Click");
Type tDelegate = evClick.EventHandlerType;
MethodInfo miHandler=
btnSave.GetType().GetMethod("Click",
BindingFlags.NonPublic | BindingFlags.Instance);
Delegate d = Delegate.CreateDelegate(tDelegate, btnSave, miHandler);
MethodInfo addHandler = evClick.GetAddMethod();
Object[] addHandlerArgs = { d };
addHandler.Invoke(exFormAsObj, addHandlerArgs);
但miHandler
变量始终为空!
注意我关心的主要问题是如何在运行时调用特定控件的事件,有没有办法?例如,我想选择当用户按F1时触发哪个点击事件。
答案 0 :(得分:5)
根据问题下方的其他评论,真正的目标是通过反思提出一个事件。
我首先要说这几乎可以肯定是一个非常可怕的想法。它容易出错并且易碎;它只是在寻找错误。我推荐的是拥有许多事件处理程序(按钮点击处理程序,按键事件处理程序等)都只是调用一个常用的方法来完成你想要的实际操作。
有人说过,这是怎么做的。反思总是很脆弱,这是它的一个主要例子 - 你必须依赖.NET中事件如何工作的当前实现细节,明天可能会改变,这将停止工作。您将获得一个存储在该对象上的私有字段,该字段保存对所有订阅事件处理程序的引用,遍历每个字段并调用它。您还需要手动创建将传递的参数(如EventArgs):
var eventArgs = EventArgs.Empty; //replace with real args
var eventInfo = tExForm.GetType().GetEvent("Click", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
var eventDelegate = (MulticastDelegate)tExForm.GetType().GetField("Click", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(tExForm);
if (eventDelegate != null)
{
foreach (var handler in eventDelegate.GetInvocationList())
{
handler.Method.Invoke(handler.Target, new object[] { tExForm, eventArgs });
}
}
答案 1 :(得分:2)
您应该在BindingFlag.FlattenHierarchy
上定义Click
后加Control
,而不是Button
。
EventInfo miHandler =
btnSave.GetType(). GetEvent("Click",
BindingFlags.FlattenHierarchy | BindingFlags.Instance);