2012-11-19 26 views
1

我有一個Windows Phone頁面(MainPage),並且在代碼隱藏中,我想動態地添加一個事件處理程序 - 例如MouseEnter事件。訣竅是,我希望這個事件處理程序有事件參數作爲一個對象:AddEventHandler當事件處理程序參數是方法中的對象時

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調用?

任何幫助,高度讚賞。

回答

1

關鍵字是委託協方差:

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; 
} 
+1

要使用非靜態的MyMethod,例如如果將它移動到Test並將其「static」更改爲「public」,則將'var te = Delegate.CreateDelegate(e.EventHandlerType,new EventHandler(MyMethod).Method);'var var = Delegate.CreateDelegate e.EventHandlerType,t,new EventHandler(t.MyMethod).Method);'。剛剛花了一段時間弄清楚這一點,並希望分享。 – ulatekh

1

看起來您需要使用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); 
} 
0

匿名方法包裹它應該做的伎倆: this.MouseEnter + =(S,E)=>一個MyEventHandler(S,E);

+0

對不起,這是不行的 - 我沒有訪問事件屬性,這就是爲什麼我要使用反射。另外,我只能使用反射來訪問事件的參數類型。 我有這個的原因。上面的鼠標輸入是爲了說明我想用反射來實現,因爲它不可能做其他事情。 –

相關問題