對.NETFramework"事件"機制理解的代碼分析

發表于:2007-05-25來源:作者:點擊數: 標簽:代碼事件機制理解
下面的文章是我自認為對"事件"機制理解比較透徹的后寫的代碼分析,但寫完之后,鄙人又惟恐理解有所偏差,所以特貼出來讓各位高手指教一二,若能讓發現理解錯誤之處,將不勝感激(此問完全乃本人"獨立自主"之作,絕非抄襲) 同時我相信此文對c#初學者也有一定幫助! 為

下面的文章是我自認為對"事件"機制理解比較透徹的后寫的代碼分析,但寫完之后,鄙人又惟恐理解有所偏差,所以特貼出來讓各位高手指教一二,若能讓發現理解錯誤之處,將不勝感激(此問完全乃本人"獨立自主"之作,絕非抄襲)

同時我相信此文對c#初學者也有一定幫助!

為了闡述清晰,特舉例說明;
該范例是在一個控件中完全自定義一組事件,并在另外的程序集中對事件被激發作出反映(也就是事件被激發后調用預先定義好的方法).

一.含有自定義事件的控件主體代碼及對應剖析 (注意,此控件庫是由VS.NET的"新建"->"Windows控件庫"生成的)

namespace MyEventTEST
{
 public class LoginEventArgs : System.EventArgs
        // 上面代碼定義了在主程序中引發事件時需要傳遞給主程序的所有信息,并且注意,
        // 該類必須派生于System.EventArgs類
 {
  public LoginEventArgs(string sUserID, string sPassword, bool bValid)
  {
   UserID = sUserID;
   Password = sPassword;
   Valid = bValid;
  }

  public string UserID;
  public string Password;
  public bool Valid;
 }

 public delegate void GoodLoginEventHandler(object sender, LoginEventArgs e);
 public delegate void FailedThreeTimesEventHandler(object sender, LoginEventArgs e);
        // 上面兩行代碼定義了兩個多路委托(因此返回類型必須為void),每個委托對應一種類型的事件;
        // 因為是多路委托,所以每個委托中可以含有多個方法.
        // 請注意,參數是(object sender, LoginEventArgs e),所以添加到多路委托的方法必須符合這種簽名方式.
        // 此外,為什么這里不使用系統已經定義的多路委托"System.EventHandler(object sender, EventArgs e)",
        // 而要自己定義新的委托"?????EventHandler()"呢?這是因為我們這里傳遞給用戶程序集的參數不是
        // "System.EventArgs"類型,而是自己定義的"LoginEventArgs"類型,所以有必要重新定義自己的委托類型.


 public class ActiveLogin : System.Windows.Forms.UserControl
 {
        private System.Windows.Forms.Label label1;
  private System.Windows.Forms.Label label2;
  private System.Windows.Forms.TextBox txtUserID;
  private System.Windows.Forms.TextBox txtPass;
  private System.Windows.Forms.Button btnLogin;
  private System.Windows.Forms.Button btnCancel;
  private System.ComponentModel.Container components = null;
                // 上面代碼是組成這個控件的一些組件定義,由VS.NET自動生成

  public event GoodLoginEventHandler GoodLogin;
  public event FailedThreeTimesEventHandler FailedThreeTimes;
  public event EventHandler Cancel;
                // 上面三行代碼非常之重要,定義了三個事件(event),分別是"GoodLogin","FailedThreeTimes"
                // 和"Cancel"
                // 它們的類型分別是"GoodLoginEventHandler","FailedThreeTimesEventHandler"
                // 和"EventHandler",也就是說添加到這三個事件中的方法必須符合對應的多路委托定義!
                // 而且注意,因為事件"Cancel"的類型是系統已經定義的多路委托"EventHandler"類型,
                // 所以上面的多路委托中沒有定義類似"CancelEventHandler"的新委托,因為是不需要的.
               
  public ActiveLogin()
  {
   InitializeComponent();
  }
                // 上面代碼是控件中類"ActiveLogin"的構造方法,該方法中調用了初始方法InitializeComponent()
                // 上面代碼由VS.NET自動生成

  protected override void Dispose( bool disposing )
  {
   if( disposing )
   {
    if(components != null)
    {
     components.Dispose();
    }
   }
   base.Dispose( disposing );
  }
                // 上面代碼是自定義控件中類"ActiveLogin"的析構方法,由VS.NET自動生成.

  private void InitializeComponent()
  {
                  ....  // 這里是對所有引用控件(組件)的初始化代碼
                }
                // 上面代碼是自定義控件中類"ActiveLogin"的初始方法,其中內容由VS.NET自動生成.

  protected virtual void OnGoodLogin(LoginEventArgs e)
                // 上面一行代碼定義了激發"GoodLogin"事件的方法;
                // 注意簽名類型,定義方法是protected virtual,也就是說只能在這個類及它的
                // 繼承類中訪問此方法,而且可以重寫.
                // 參數類型是"LoginEventArgs",注意只有這一個參數,因為在本方法中含有對
                // this的引用,所以這里不需要傳遞this對象.
                // 一般地說,這個方法使用場合只有兩種:
                //     <1>在本控件內被調用,因為本方法不被調用,就無法激發用戶代碼在事件"GoodLogin"
                //        中添加的方法;
                //     <2>在用戶的繼承代碼中重寫本方法,雖然重寫本方法可能會帶來性能的提高,但
                //        倘若用戶代碼中忘記調用此方法,那么在用戶代碼先前在事件"GoodLogin"中
                //        添加的方法將無法得到激活!!! (避免此問題的方法就是在重寫方法中必須含有
                //        一行"base.GoogLogin(e)",這行將負責調用本方法)
                //        對于第<2>點需要提出的是,在用戶的繼承代碼中重寫本方法的作用相當與在
                //        事件"GoodLogin"中添加一個方法,此方法的代碼內容和重寫方法內容相同.
                //        (但是應該絕對沒有"base.GoogLogin(e)"這一行)
  {
   if (GoodLogin != null)  // 如果在事件"GoogLogin"中含有方法,則激發這些方法
   {
    GoodLogin(this, e);  // 把this對象和參數e傳遞給所有在事件"GoogLogin"
                                                     // 中添加的方法,并順序執行這些方法 (注意,由多路
                                                     // 委托特性決定:在用戶代碼中先添加的方法先執行.
   }
  }
                // 上面對OnGoogLogin方法解釋已經十分詳細了,下面兩個ON方法均與上述ON方法同出一轍.

  protected virtual void OnFailedThreeTimes(LoginEventArgs e)
  {
   if (FailedThreeTimes != null)
   {
    FailedThreeTimes(this, e);
   }
  }

  protected virtual void OnCancel(System.EventArgs e)
  {
   if (Cancel != null)
   {
    Cancel(this, e);
   }
  }
              
  private void btnLogin_Click(object sender, System.EventArgs e)
                // 上面的定義是由VS.NET自動生成,是當按下控件的"btnLogin"按鈕時調用的方法.
  {
                       if(...)
                          OnGoodLogin(new LoginEventArgs(txtUserID.Text, txtPass.Text, true));
                          // 上面一行代碼調用了OnGoodLogin方法,作用是"當控件中的按鈕btnLogin被按下時,
                          // 并且符合上面的if條件時:
                          // 將通過調用OnGoodLogin方法把在用戶代碼中添加到事件"GoogLogin"中的所有方法
                          // 全部順序執行一遍.
                          // 為什么不在這里把OnGoodLogin()方法中的代碼執行一遍,而還要再單獨調用OnGoodLogin
                          // 方法呢? 這是因為有時候用戶代碼需要重寫OnGoodLogin()方法!
                          // 下面調用的OnFailedThreeTimes()方法和OnCancel()方法解釋同上.
                       else
     OnFailedThreeTimes(new LoginEventArgs(txtUserID.Text, txtPass.Text, false));
  }

  private void btnCancel_Click(object sender, System.EventArgs e)
  {
   OnCancel(new EventArgs());
  }
 }
}

二.調用此控件的程序集(注意,此程序集是由VS.NET的"新建"->"Windows應用程序"生成的),也就是"用戶代碼"部分

namespace HostApp
{
 public class Form1 : System.Windows.Forms.Form
 {
  private MyEventTEST.ActiveLogin activeLogin1;
                // 上面一行代碼引用了自定義控件庫的類"ActiveLogin",并用它定義了一個對象"activeLogin1".
                //  這里的"MyEventTEST"是在自定義的控件庫中定義的命名空間,如果在這個程序集中沒有出現
                //  "using MyEventTEST"語句,則該名稱必須出現在對自定義控件引用的任何代碼中!

  private System.ComponentModel.Container components = null;

  public Form1()
  {
   InitializeComponent();
  }

  protected override void Dispose( bool disposing )
  {
   if( disposing )
   {
    if (components != null)
    {
     components.Dispose();
    }
   }
   base.Dispose( disposing );
  }
                // 上面兩個方法都是又VS.NET自動生成,不做另外解釋.

  private void InitializeComponent()
  {
   this.activeLogin1 = new MyEventTEST.ActiveLogin();
                        // 上面一行代碼用自定義控件庫中的類"ActiveLogin"實例化對象"activeLogin1"
   this.SuspendLayout();

                        //
   // activeLogin1
   //
   this.activeLogin1.Location = new System.Drawing.Point(144, 8);
   this.activeLogin1.Name = "activeLogin1";
   this.activeLogin1.Size = new System.Drawing.Size(280, 184);
   this.activeLogin1.TabIndex = 0;

   this.activeLogin1.GoodLogin += new MyEventTEST.GoodLoginEventHandler(this.activeLogin1_GoodLogin);
   this.activeLogin1.Cancel += new System.EventHandler(this.activeLogin1_Cancel);
   this.activeLogin1.FailedThreeTimes += new MyEventTEST.FailedThreeTimesEventHandler(this.activeLogin1_FailedThreeTimes);
                        // !!! 請注意上面的三行代碼,這是用戶代碼接受自定義控件庫中事件的代碼 !!!
                        // 上面三行代碼分別把用戶定義的方法"activeLogin1_GoodLogin","activeLogin1_Cancel"
                        // 和"activeLogin1_FailedThreeTimes"分別添加到自定義控件中的事件"GoogLogin","Cancel"
                        // 和"FailedThreeTimes"中; 這樣一來只要自定義控件中的對應事件一被激發,這些
                        // 添加用戶自定義方法就會被執行.
                        // 要注意的是,用戶自定義方法簽名必須符合對應的多路委托的定義(因為事件是由多路委托
                        // 定義的,所以要添加到什么事件,定義就必須符合該事件對應的多路委托的定義)
                        // 而且,這里的Cancel事件類型是系統已經定義的多路委托"EventHandler"類型,所以它的實例化
                        // 與其它兩個事件的實例化有所不同,是"System.EventHandler",而不是"MyEventTEST.EventHandler"!
                        // 這些用戶自定義方法將在下面列出.
                        // 不過請注意,上面的三行代碼雖然在方法InitializeComponent()中,但卻是我們自己手工添加的!

   //
   // Form1
   //
   this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
   this.ClientSize = new System.Drawing.Size(440, 357);
   this.Controls.AddRange(new System.Windows.Forms.Control[] {
             this.activeLogin1,
            });
   this.Name = "Form1";
   this.Text = "Form1";
   this.ResumeLayout(false);
  }

  [STAThread]
  static void Main()
  {
   Application.Run(new Form1());
  }
                // 上面的方法分別是Windows Forms程序的入口.

  private void activeLogin1_GoodLogin(object sender, MyEventTEST.LoginEventArgs e)
  {
   MessageBox.Show("Good Login! " + e.UserID);
  }

  private void activeLogin1_FailedThreeTimes(object sender, MyEventTEST.LoginEventArgs e)
  {
   MessageBox.Show("Failed to login three times.");
  }

  private void activeLogin1_Cancel(object sender, System.EventArgs e)
  {
   MessageBox.Show("Cancel");
  }
                // 上面的三個方法(activeLogin1_GoogLogin,activeLogin1_Cancel和activeLogin1_FailedThreeTimes)
                // 就是當自定義控件中對應的事件被激發時在當前程序集中對應的處理方法.
                // 值得注意的是,簽名應該完全符合對應的多路委托的定義!
 }
}

原文轉自:http://www.anti-gravitydesign.com

評論列表(網友評論僅供網友表達個人看法,并不表明本站同意其觀點或證實其描述)
国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97