C#(WPF)去除事件中註冊的事件處理方法!

在WPF中,移除一個事件中已經註冊的處理方法,看似簡單,實際仍是很痛苦的一件事情。由於C#的靈活性,定義事件的方法也是多種多樣。
我本身定義了一個事件:this

public event EventHandler TestEvent;

當我想註銷這個事件上註冊的全部方法的時候,我能夠按以下的方法進行code

Delegate[] dels = TestEvent.GetInvocationList();
            foreach (var d in dels)
            {
                TestEvent-= d as EventHandler;
            }

可是,當我想註銷一個Window上的Closed上註冊的事件時,發如今Closed上根本沒有GetInvocationList方法。這是怎麼回事呢。經過反編譯查看微軟的代碼,它的定義是這樣的:對象

public event EventHandler Closed
{
    add{}
    remove{}
}

坑爹啊。度娘了半天,終於找到下面的方法參考完成。事件

/// <summary>
/// 清除一個對象的某個事件所掛鉤的delegate
/// </summary>
/// <param name="ctrl">控件對象</param>
/// <param name="eventName">事件名稱,默認的</param>
public static void ClearEvents(this object ctrl, string eventName = "_EventAll")
{
    if (ctrl == null) return;
    BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Static;
    EventInfo[] events = ctrl.GetType().GetEvents(bindingFlags);
    if (events == null || events.Length < 1) return;

    for (int i = 0; i < events.Length; i++)
    {
        try
        {
            EventInfo ei = events[i];
            //只刪除指定的方法,默認是_EventAll,前面加_是爲了和系統的區分,防之後雷同
            if (eventName != "_EventAll" && ei.Name != eventName) continue;

            /********************************************************
             * class的每一個event都對應了一個同名(變了,前面加了Event前綴)的private的delegate類
             * 型成員變量(這點能夠用Reflector證明)。由於private成
             * 員變量沒法在基類中進行修改,因此爲了可以拿到base 
             * class中聲明的事件,要從EventInfo的DeclaringType來獲取
             * event對應的成員變量的FieldInfo並進行修改
             ********************************************************/
            FieldInfo fi = ei.DeclaringType.GetField("Event_" + ei.Name, bindingFlags);
            if (fi != null)
            {
                // 將event對應的字段設置成null便可清除全部掛鉤在該event上的delegate
                fi.SetValue(ctrl, null);
            }
        }
        catch { }
    }
}

原來的代碼中 ei.DeclaringType.GetField("Event_" + ei.Name, bindingFlags);的Event後面沒有下劃線,即寫成了「Event」,執行時發現fi是空。參考上面的代碼「_EventAll」,加一個下劃線嘗試。成功!rem

相關文章
相關標籤/搜索