2012年8月16日 星期四

C# - 如何複製其他物件的事件


之前遇到了要強制驅動物件的事件【C# 如何強制驅動物件的事件?】,
也遇到了要移除物件的事件【C# - 如何移除未知名稱的事件 - LookupEdit.KeyDown 】,
正所謂無三不成禮,這次要做的是複製其他物件的事件!
說複製其實不太對,正確地來說應該是把其他物件的事件掛(delegate)上來。

例如我們可能在 A 物件寫了一個 KeyDown 的程式,


private void ObjectA_KeyDown(object sender, KeyEventArgs e)


在 designer 裡面會是寫成這樣,


this. ObjectA.KeyDown += new
System.Windows.Forms.KeyEventHandler(this. ObjectA_KeyDown);


當我們的 B 物件也要用同一個事件的時候,我們只要手動用 += 就可以掛上這個事件了!
但是問題又來了,如果我們不知道他事件的名稱,那我們要怎掛?
其實前面一大段程式都跟之前移除事件的程式一樣,
只是後面要怎麼掛上去呢?說穿了很簡單!
(其實是會寫之後才覺得簡單 XD)
程式如下,跟之前程式最大的差別就是最後面兩行,




private void CopyEvents(Control source, Control dest)
{
    FieldInfo keyDownInfo = (typeof(Control)).GetField("EventKeyDown",
            BindingFlags.Static | BindingFlags.NonPublic);

    FieldInfo eventsInfo = (typeof(Component)).GetField("events",
        BindingFlags.Instance | BindingFlags.NonPublic);

    object keyDown = keyDownInfo.GetValue(source);

    EventHandlerList events = eventsInfo.GetValue(source) as EventHandlerList;

    if (events == null) return;

    KeyEventHandler handler = events[keyDown] as KeyEventHandler;

    Delegate d = events[keyDown];

    if (d != null)
    {
        events.RemoveHandler(keyDown, d);
    }

    EventHandlerList eventsDest = eventsInfo.GetValue(dest) as EventHandlerList;

    eventsDest.AddHandler(keyDown, d);
           
}


最後的兩行其實就是得到目標物件的 EventHandlerList ,
然後用 AddHandler 掛上去就 OK 了!測試過也沒問題!

其實我覺得最困難的是要找到那個事件的關鍵字,
像我這次本來是要用 DateEdit.PopUp 來測試的,
結果花了 1hr 還是找不到 PopUp 的關鍵字,
所以先退而求其次用 KeyDown 先來驗證看看是不是可以掛載上去。

會有這樣的需求是因為我想要複製別的 UI 的屬性、事件,
不過目前 UI 的屬性複製失敗,看來沒有辦法用迴圈的方式把所有的是屬性都複製,
只能夠針對個別的物件慢慢複製,這個部分還有得搞!
然後複製事件也遇到了難關,
因為 EventHandlerList 沒有辦法用 foreach ,
所以也只能一個一個事件慢慢複製,
這個就真的有麻煩到,不過應該還有其他招;
但是原本在取得 FieldInfo 就要指定 Class ,
所以看來頂多也是半自動這樣!
唉~~~有空再慢慢搞吧!

沒有留言:

張貼留言