淺析C# 中object sender與EventArgs e (轉)

 轉自:http://hi.baidu.com/jiangyangw3r/blog/item/e2dbd3c8690bb41f7f3e6fc3.html

一、瞭解C#中的預定義事件處理機制

    在寫代碼前我們先來熟悉.net框架中和事件有關的類和委託,瞭解C#中預定義事件的處理。

EventArgs是包含事件數據的類的基類,用於傳遞事件的細節。

EventHandler是一個委託聲明如下

public delegate void EventHandler( object sender , EventArgs e)

注意這裏的參數,前者是一個對象(其實這裏傳遞的是對象的引用,如果是button1的click事件則sender就是button1),後面是包含事件數據的類的基類。

下面我們研究一下Button類看看其中的事件聲明(使用WinCV工具查看),以Click事件爲例。

public event EventHandler Click;

這裏定義了一個EventHandler類型的事件Click

前面的內容都是C#在類庫中已經爲我們定義好了的。下面我們來看編程時產生的代碼。

private void button1_Click(object sender, System.EventArgs e)
         {
             ...
         }

這是我們和button1_click事件所對應的方法。注意方法的參數符合委託中的簽名(既參數列表)。那我們怎麼把這個方法和事件聯繫起來呢,請看下面的代碼。

this.button1.Click += new System.EventHandler(this.button1_Click);

把this.button1_Click方法綁定到this.button1.Click事件。

下面我們研究一下C#事件處理的工作流程,首先系統會在爲我們創建一個在後臺監聽事件的對象(如果是 button1的事件那麼監聽事件的就是button1),這個對象用來產生事件,如果有某個用戶事件發生則產生對應的應用程序事件,然後執行訂閱了事件 的所有方法。

二、簡單的自定義事件(1)

首先我們需要定義一個類來監聽客戶端事件,這裏我們監聽鍵盤的輸入。

定義一個委託。

public delegate void UserRequest(object sender,EventArgs e);

前面的object用來傳遞事件的發生者,後面的EventArgs用來傳遞事件的細節,現在暫時沒什麼用處,一會後面的例子中將使用。

下面定義一個此委託類型類型的事件

 public event UserRequest OnUserRequest;

 下面我們來做一個死循環

 public void Run()
      {
        bool finished=false;
         do
          {
           if (Console.ReadLine()=="h")
           {
            OnUserRequest(this,new EventArgs());
           } 
          }while(!finished);
          }

此代碼不斷的要求用戶輸入字符,如果輸入的結果是h,則觸發OnUserRequest事件,事件的觸發者是本身(this),事件細節無(沒有傳遞任何參數的EventArgs實例)。我們給這個類取名爲UserInputMonitor。

下面我們要做的是定義客戶端的類
    首先得實例化UserInputMonitor類

 UserInputMonitor monitor=new UserInputMonitor();

 然後我們定義一個方法。

 private void ShowMessage(object sender,EventArgs e)
       {
           Console.WriteLine("HaHa!!");
       }

 最後要做的是把這個方法和事件聯繫起來(訂閱事件),我們把它寫到客戶端類的構造函數裏。

Client(UserInputMonitor m)
      {
        m.OnUserRequest+=new    UserInputMonitor.UserRequest(this.ShowMessage);
       //m.OnUserRequest+=new m.UserRequest(this.ShowMessage);

       //注意這種寫法是錯誤的,因爲委託是靜態的
      }

 下面創建客戶端的實例。

  new Client(monitor);

  對了,別忘了讓monitor開始監聽事件。

  monitor.run();

  大功告成,代碼如下:

  using System;
       class UserInputMonitor
      {
        public delegate void UserRequest(object sender,EventArgs e);
       //定義委託
        public event UserRequest OnUserRequest;
       //此委託類型類型的事件
        public void Run()
       {
            bool finished=false;
         do
         {
           if (Console.ReadLine()=="h")
            {
           OnUserRequest(this,new EventArgs());
            }  
         }while(!finished);
     }
}

  public class Client
   {
      public static void Main()
        {
           UserInputMonitor monitor=new UserInputMonitor();
           new Client(monitor);
            monitor.Run();
        }
   private void ShowMessage(object sender,EventArgs e)
     {
        Console.WriteLine("HaHa!!");
     }
     Client(UserInputMonitor m)
       {
         m.OnUserRequest+=new     UserInputMonitor.UserRequest(this.ShowMessage);
         //m.OnUserRequest+=new m.UserRequest(this.ShowMessage);
        //注意這種寫法是錯誤的,因爲委託是靜態的
        }
    }

三、進一步研究C#中的預定義事件處理機制

    可能大家發現在C#中有些事件和前面的似乎不太一樣。例

private void textBox1_KeyPress(object sender,System.Windows.Forms.KeyPressEventArgs e)
       {

       }

 this.textBox1.KeyPress+=newSystem.Windows.Forms.KeyPressEventHandler(this.textBox1_KeyPress);

這裏使用了KeyPressEventArgs而不是EventArgs作爲參數。這裏使用了KeyEventHandler委託,而不是EventHandler委託。

KeyPressEventArgs是EventArgs的派生類,而KeyEventHandler的聲明如下

public delegate void KeyEventHandler( object sender , KeyEventArgs e );

是參數爲KeyEventArgs的委託。那爲什麼KeyPress事件要這麼做呢,我們可以從兩個類的構造函數來找答案。

public EventArgs();

public KeyPressEventArgs(char keyChar);

這裏的keyData是什麼,是用來傳遞我們按下了哪個鍵的,哈。

我在KeyEventArgs中又發現了屬性

public char KeyChar { get; }

 進一步證明了我的理論。下面我們來做一個類似的例子來幫助理解。

四、簡單的自定義事件(2)

    拿我們上面做的例子來改。

    我們也定義一個EventArgs(類似KeyEventArgs)取名MyEventArgs,定義一個構造函數public MyEventArgs(char keyChar),同樣我們也設置相應的屬性。代碼如下

 

using System;
class MyMyEventArgs:EventArgs
{
 private char keyChar;
 public MyMyEventArgs(char keyChar)
 {
  this.keychar=keychar;
 }
 public char KeyChar
 {
  get
  {
   return keyChar;
  }
 }
}

因爲現在要監聽多個鍵了,我們得改寫監聽器的類中的do...while部分。改寫委託,改寫客戶端傳遞的參數。好了最終代碼如下,好累

using System;
class MyEventArgs:EventArgs
{
 private char keyChar;
 public MyEventArgs(char keyChar)
 {
  this.keyChar=keyChar;
 }
 public char KeyChar
 {
  get
  {
   return keyChar;
  }
 }
}

class UserInputMonitor
{
 public delegate void UserRequest(object sender,MyEventArgs e);
 //定義委託
 public event UserRequest OnUserRequest;
 //此委託類型類型的事件
 public void Run()
 {
  bool finished=false;
  do
  {
   string inputString= Console.ReadLine();
   if (inputString!="")
    OnUserRequest(this,new MyEventArgs(inputString[0]));
  }while(!finished);
 }
}

public class Client
{
 public static void Main()
 {
  UserInputMonitor monitor=new UserInputMonitor();
  new Client(monitor);
  monitor.Run();
 }
 private void ShowMessage(object sender,MyEventArgs e)
 {
  Console.WriteLine("捕捉到:{0}",e.KeyChar);
 }
 Client(UserInputMonitor m)
 {
  m.OnUserRequest+=new UserInputMonitor.UserRequest(this.ShowMessage);
  //m.OnUserRequest+=new m.UserRequest(this.ShowMessage);
  //注意這種寫法是錯誤的,因爲委託是靜態的
 }
}

發佈了41 篇原創文章 · 獲贊 10 · 訪問量 31萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章