通过反思获得活动

时间:2014-05-09 15:03:55

标签: c# reflection

我试图通过反射获取按钮的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时触发哪个点击事件。

2 个答案:

答案 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);