基於Windows的應用程式也是基於訊息的,Windows使用預定義訊息與應用程式通訊。
.NET Framework將Windows訊息封裝在事件中,可以把事件作為對象之間的通訊介質。
事件發送方:發送事件的對象
事件接收方:捕獲事件並對其作出響應的對象(處理事件)
在事件通訊機制中,事件發送方不知道哪個對象將接收到它引發的事件以及進行什麼樣的處理,事件
發送方不知道誰將是事件接收方,它只是將"事件發生了"這個訊息廣播出去。
在C#中,事件機制是藉助委託來實現的。一個事件就相當於一個委託執行個體。
----------------------------------------------------------------------
使用事件:使用事件分為4步,與使用委託有一點小區別。
1.定義一個委託類型。
這一步與使用委託沒有什麼不同,一般都使用 .Net預定義的委託。
2.定義一個事件名(在事件發送方中)。
存取控制符 event 委託類型名 事件名;
3.封裝事件,即將事件處理方法註冊到事件中(事件處理方法定義在事件接收方中)。
事件發送方.事件名 += new 委託類型名(事件處理方法);
事件名即相當於委託執行個體名,事件處理方法即相當於委託執行個體的關聯方法。只不過,在事件機制中,將定義委託執行個體(使用委託的第二步)分為兩個步驟,分別由事件發送方和接收方來進行: 定義一個事件名 - 得到一個委託執行個體名 (事件發送方) ;封裝該事件 - 得到一個關聯方法(將一個事件處理方法與一個事件關聯) (事件接收方)。
註:在事件發送方定義事件名時,可以將事件名聲明為static的,以便事件接收方封裝事件
4.事件發送方引發事件,事件接收方的事件處理方法捕獲並處理事件。
引發事件(相當於調用委託執行個體)即會導致事件處理方法的執行(相當於委託執行個體的關聯方法的執行)
事件可能由使用者的操作(比如單擊滑鼠)引發,也可能由某些其他的程式邏輯觸發;
--------------------------------------------------------------------
using System;namespace EventExample{ class ClassReceive //事件接收方 { [STAThread] static void Main(string[] args) { ClassSend Send = new ClassSend(); //3.封裝事件 Send.CalculateFinished += new MyDelegate(Send_CalculateFinished); //執行下面三行,將導致三次引發MyClass的CalaculatedFinished事件 Send.Square(2); //呼叫事件發送方的代碼,導致事件被引發 Send.Cube(2); //呼叫事件發送方的代碼,導致事件被引發 Send.Double(2); //呼叫事件發送方的代碼,導致事件被引發 } //定義事件處理方法,在事件被引發後執行 private static void Send_CalculateFinished(string msg) { Console.WriteLine(msg + "計算完成"); } } //1.定義委託,指定傳回型別和形參列表。與類定義一樣,同在命名空間下 delegate void MyDelegate(string msg); class ClassSend //事件發送方 { //2.定義事件CalculateFinished,該事件屬於ClassSend類 public event MyDelegate CalculateFinished; //4.執行該方法事件將被引發,一般由事件接受方調用該方法來觸發事件 public void OnCalculateFinished(string msg) { //判斷事件是否為空白,事件接受方如果定義了事件的處理方法,則不為null if (CalculateFinished != null) { //如果事件為空白就觸發事件,將導致一個Null 參考異常 CalculateFinished(msg); //就是這一句引發事件,即: 事件名(形參列表); //此方法的形參列表已經由與事件相關的委託指定了 } } public void Square(float x) { float result = x * x; Console.WriteLine("{0}的平方等於:{1}", x, result); //執行事件引發方法,將導致事件被引發 OnCalculateFinished("平方"); } public void Cube(float x) { float result = x * x * x; Console.WriteLine("{0}的立方等於:{1}", x, result); //執行事件引發方法,將導致事件被引發 OnCalculateFinished("立方"); } public void Double(float x) { float result = 2 * x; Console.WriteLine("{0}的倍數等於:{1}", x, result); //執行事件引發方法,將導致事件被引發 OnCalculateFinished("倍數"); } }}
--------------------------------------------------------------------
事件是多點委託,對事件只能使用 += 和 -= 運算,= 運算對於事件是無效的。
.NET 提供了一個預定義的用於事件的委託類型 - EventHandler
public delegate void EventHandler(Object sender,EventArgs e);
參數sender是引發事件的事件發送方對象,e是事件的有關資料
在定義事件時,可以不必自訂委託類型,直接使用這個預定義的事件委託類型就可以了。
自訂事件時,應該遵守一些命名規範:
使用動詞命名事件,最好帶上現在、進行或完成時態來描述事件的觸發時效;
事件的委託類型的命名一般以"EventHandler"為尾碼,事件參數類名稱以"EventArgs"為尾碼;
總是使用 sender 和 e 來命名事件中的兩個參數;
事件發送方中,引發事件的方法的命名一般用 On + 事件名 eg:OnCalaculateFinished(string msg);
在事件發送方類中,定義引發事件的方法(其中包含呼叫事件的語句)時,必須先判斷事件是否為空白,因為事件是在接收方中封裝的(定義事件處理方法),事件發送方無法知曉是否存在有事件處理方法(發送方不知道接收方的存在),所以在事件發送方中引發事件的代碼處,必須先判斷事件是否為空白。另外,往往是在事件接收方中,調用了事件發送方的代碼,然後導致事件被引發,因而,在事件接收方中,封裝事件的代碼應該先於呼叫事件發送方的代碼執行。