[英]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.