【问题标题】:Bind a delegate to an event dynamically将委托动态绑定到事件
【发布时间】:2013-10-02 08:45:02
【问题描述】:

我有一个方法可以将页面上的方法绑定到动态创建的LinkButtons。

protected virtual void AddDynamicHandlerToControl(Page page, Control controlInstance,
            string methodName, string eventName)
{
   Delegate d = null;

   EventInfo ei = controlInstance.GetType().GetEvent(eventName);

   Type tDelegate = ei.EventHandlerType;

   MethodInfo method = page.GetType().BaseType.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);

   if (method != null)
      d = Delegate.CreateDelegate(tDelegate, page, method);
   else {
      FieldInfo field = page.GetType().BaseType.GetField(methodName, BindingFlags.NonPublic | BindingFlags.Instance);

      if (field != null)
      {
         d = field.GetValue(page) as Delegate;
      }
   }

   MethodInfo addHandler = ei.GetAddMethod();
   object[] addHandlerArgs = { d };
   addHandler.Invoke(controlInstance, addHandlerArgs);
}

这适用于该页面内的方法。我想添加的是对用户控件内部方法的支持。所以我在页面代码隐藏中创建了一个delegate,并在运行时为其分配了用户控制方法。

我这样创建和分配委托:

protected event PrintPageMethod PrintPage;
protected delegate void PrintPageMethod(object sender, EventArgs e);

然后:

PrintPage = DetailedTestsResult1.UserActionsForTests1_PrintPage;

代码尝试查找方法,当找不到方法时,它会尝试为委托查找字段并找到正确的委托,该委托以用户控件类为目标指向正确的方法。

问题是当到达addHandler.Invoke(controlInstance, addHandlerArgs);时,它会抛出异常

“SomePage+PrintPageMethod”类型的对象无法转换为“System.EventHandler”类型。

我不知道我做错了什么。

【问题讨论】:

  • 显示完整的用户控件(事件相关的东西)
  • @jgauffin - 我会添加用户控件代码,但由于委托是指向函数的指针,我看不到显示函数本身的相关性。例外不是将函数分配给委托,而是将委托分配给事件处理程序。

标签: c# reflection delegates


【解决方案1】:

代替:

protected event PrintPageMethod PrintPage;
protected delegate void PrintPageMethod(object sender, EventArgs e);

使用:

protected event EventHandler PrintPage;

尽管签名相似,但委托类型是不同的。

【讨论】:

  • 这似乎是一种解决方法,而不是修复方法。该代码似乎应该看到PrintPage 事件的类型为PrintPageMethod 并创建一个PrintPageMethod 委托。
  • 谢谢!如果这是一种解决方法(我仍然不明白为什么使用委托不起作用),那么这解决了我的问题。
【解决方案2】:

您不能将委托投给其他委托。

d = field.GetValue(page) as Delegate;

Delegate orig = field.GetValue(page) as Delegate;
d = Delegate.Combine(
    orig.GetInvocationList()
    .Select(_ => Delegate.CreateDelegate(tDelegate, _.Target, _.Method))
    .ToArray()
    );

您可以使用来自.Target.Method 的调用目标创建另一个Delegate,如果Delegate 有很多目标,您必须合并每个delegate。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多