C# 基礎知識系列]專題六:.net WinForm 控件的事件委託剖析

首先從controlInstance.Click事件開始. 用Reflector反編譯System.Windows.Forms.Control類可以看到對Click事件的定義:

        [System.Windows.Forms.SRCategory("CatAction"), System.Windows.Forms.SRDescription("ControlOnClickDescr")]
        public event EventHandler Click
        {
            add
            {
                base.Events.AddHandler(Control.EventClick, value);
            }

            remove
            {
                base.Events.RemoveHandler(Control.EventClick, value);
            }

        }

這裏的Control.EventClick是一個只讀的靜態私有屬性,它是以後事件查找委託的鍵(key),請記住這個.

 

private static readonly object EventClick = new object();

Control的Events屬性是由System.ComponentModel.Component 繼承而來,它是EventHandlerList的實例.

private EventHandlerList events;
protected EventHandlerList Events
{
      get
      {
            if (this.events == null)
            {
                  this.events = new EventHandlerList();
            }

            return this.events;
      }

}

EventHandlerList類有三個重要的方法:

      public void AddHandler(object key, Delegate value);
      public void RemoveHandler(object key, Delegate value);
      private ListEntry Find(object key);

 AddHandler的作用是插入一個鍵和一個委託類型的值, 插入之前通過Find方法檢查一下同樣的委託對象是否存在,如果存在,則合併; 如果不存在,以要插入的委託對象(value)爲頭.

public void AddHandler(object key, Delegate value)
{
      EventHandlerList.ListEntry entry1 = this.Find(key);
      if (entry1 != null)
      {
            entry1.handler = Delegate.Combine(entry1.handler, value);
      }

      else
      {
            this.head = new EventHandlerList.ListEntry(key, value, this.head);
      }

}

 

如果是一個按鈕的Click事件,我們一般定義爲:

button1.Click += new EventHandler(OnButtonClick);

protected void OnButtonClick(object sender, System.EventArgs e)
{
    // 你的處理函數
}

則通過了button1.Events.AddHandler(Control.EventClick,  EventHandler handler),而這個handler卻是一個MulticastDelegate的實例。看MS公佈的.net framework 部分源碼就知道了:

// ==++==
// 
//   
//    Copyright (c) 2002 Microsoft Corporation.  All rights reserved.
//   
//    The use and distribution terms for this software are contained in the file
//    named license.txt, which can be found in the root of this distribution.
//    By using this software in any fashion, you are agreeing to be bound by the
//    terms of this license.
//   
//    You must not remove this notice, or any other, from this software.
//   
// 
// ==--==
namespace System {
    
    using System;
    /// <include file='doc\EventHandler.uex' path='docs/doc[@for="EventHandler"]/*' />
     [Serializable()]
    public delegate void EventHandler(Object sender, EventArgs e);}

現在我們轉到對委託(Delegate)和多播委託(MulticastDelegate)的研究了。
Delegate類已經封裝好產生委託,消除委託和執行委法的方法,它是一個不能實例化的抽象類。但.net 的編譯器支持由delegate定義的類型來實例化一個Delegate對象,它能讓這個對象的執行委託方法像普通函數一樣調用(具體的可以看C#高級編程裏面的實例),所以很多時候,delegate類型會被認爲是函數指針。 
Delegate還有兩個很重要的方法,組合委託Combine和刪除委託Remove。在單播委託Delegate中使用這組合委託方法會拋出多播不支持異常(MulticastNotSupportedException)。而使用刪除委託方法時,如果這個單播委託和要刪除的委託是同一個值時,則返回null,證明已經刪除;如果不是,則原封不動返回原來的單播委託。
EventHandler實際上是一個多播委託實例,所以它支持組合委託和刪除委託的方法。這個實例,實際上是一個委託實例鏈,它是這個鏈的鏈尾。每次像調用普通函數調用這個委託的時候,這個委託會執行完委託的代理函數,並查找鏈表中上一個委託實例,執行這個委託的代理函數,再查找鏈表中上上個委託實例,執行當前委託的代理函數。。。 一直到鏈表被遍歷完。

        protected override sealed Object DynamicInvokeImpl(Object[] args)
        {
            if (_prev != null)
                _prev.DynamicInvokeImpl(args);
            return base.DynamicInvokeImpl(args);
        }


好了。那可以想象,一個用戶點擊按鈕button1,首先執行的函數是OnClick函數
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        protected virtual void OnClick(EventArgs e)
        {
            if (this.CanRaiseEvents)
            {
                EventHandler handler1 = (EventHandler) base.Events[Control.EventClick];
                if (handler1 != null)
                {
                    handler1(this, e);
                }

            }

        }
handler1就是一個多播委託, 如果不爲空,則執行它,而且這個執行就是執行所有的代理函數。這樣就明白了WinForm控件Click事件所有的始終了!
發佈了44 篇原創文章 · 獲贊 73 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章