繁体   English   中英

AddEventHandler 当事件处理程序参数是方法中的对象时

[英]AddEventHandler when event handler argument is object in method

我有一个 Windows Phone 页面 (MainPage),在代码隐藏中,我想动态添加一个事件处理程序 - 例如添加到 MouseEnter 事件。 诀窍是,我希望这个事件处理程序将事件参数作为一个对象:

    private void MyEventHandler(object sender, object args)
    {

    }

(这样做的原因是这是一个简化的例子)

这有效:

this.MouseEnter += MyEventHandler;

但这会引发 ArgumentException:

var handlerType = Type.GetType("System.EventHandler`1").
                  MakeGenericType(typeof(EventArgs));
this.GetType().GetEvent("Hold").AddEventHandler(
                  this, Delegate.CreateDelegate(handlerType, this, "MyEventHandler"));

并且异常的消息是:“无法绑定到目标方法,因为其签名或安全透明度与委托类型的签名或安全透明度不兼容。” 如果我更改事件处理程序的签名,一切正常,但我想将其保留为“对象”或“动态”。

如何使用 AddEventHandler 调用添加事件处理程序?

任何帮助都受到高度赞赏。

看起来您需要求助于 DynamicMethod 和 ILGenerator 来生成与事件处理程序签名匹配的方法。 然后在 DynamicMethod 实现中调用具有您的签名 void MyEventHandler(object, object) 的全局事件处理程序。

public MainPage()
{
   var handler = Create<MouseEventHandler>();
   this.LayoutRoot.MouseMove += handler;
}

public static void MyEventHandler(object sender, object args)
{
    Debug.WriteLine("MyEventHandler({0}, {1})", sender, args);
}

private TDelegate Create<TDelegate>()
{
    // retrieve parameter types from delegate type
    var delegateType = typeof(TDelegate);
    var invoke = delegateType.GetMethod("Invoke");
    var parameterTypes = (from p in invoke.GetParameters()
                          select p.ParameterType).ToArray();

    // create dynamic event handler having TDelegate signature
    var method = new DynamicMethod("", null, parameterTypes);
    var myEventHandlerMethod = typeof(MainPage).GetMethod("MyEventHandler");

    var generator = method.GetILGenerator();
    generator.Emit(OpCodes.Ldarg_0);
    generator.Emit(OpCodes.Ldarg_1);
    generator.Emit(OpCodes.Call, myEventHandlerMethod);    // invoke my event handler
    generator.Emit(OpCodes.Ret);

    return (TDelegate)(object)method.CreateDelegate(delegateType);
}

关键字是委托协方差:

class Program
{
  static void Main(string[] args)
  {
    var t = new Test();

    var e = t.GetType().GetEvent("TestEvent");
    var te = Delegate.CreateDelegate(e.EventHandlerType, new EventHandler(MyMethod).Method);

    e.AddEventHandler(t, te);

    t.RaiseTest();
  }

  static void MyMethod(object sender, object args)
  {

  }
}

public class Test
{
  public class MyEventArgs : EventArgs { }

  public void RaiseTest()
  {
    var e = TestEvent;
    if (e != null)
      e(this, new MyEventArgs());
  }

  public event EventHandler<MyEventArgs> TestEvent;
}

包装它的匿名方法应该可以解决问题: this.MouseEnter += (s,e) => MyEventHandler(s,e);

暂无
暂无

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

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