在發生其他類或對象關注的事情時,類或對象可通過事件通知它們。發送(或引發)事件的類稱為“發行者”,接收(或處理)事件的類稱為“訂戶”。
事件概述
事件具有以下特點:
l 發行者確定何時引發事件,訂戶確定執行何種操作來響應該事件。
l 一個事件可以有多個訂戶。一個訂戶可處理來自多個發行者的多個事件。
l 沒有訂戶的事件永遠不會被調用。
l 事件通常用於通知使用者操作(如:圖形化使用者介面中的按鈕單擊或菜單選擇操作)。
l 如果一個事件有多個訂戶,當引發該事件時,會同步調用多個事件處理常式。
l 可以利用事件同步線程。
l 在 .NET Framework 類庫中,事件是基於 EventHandler 委託和 EventArgs 基類的。
事件的實現原理
事件是對象發送的訊息,以發訊號通知操作的發生。操作可能是由使用者互動(例如按一下滑鼠)引起的,也可能是由某些其他的程式邏輯觸發的。引發事件的對象稱為事件發送方。捕獲事件並對其作出響應的對象叫做事件接收方。
在事件通訊中,事件發送方類不知道哪個對象或方法將接收到(處理)它引發的事件。所需要的是在源和接收方之間存在一個媒介(或類似指標的機制)。.NET Framework 定義了一個特殊的類型(Delegate),該類型提供函數指標的功能。
委託是可儲存對方法的引用的類。與其他的類不同,委託類具有一個簽名,並且它只能對與其簽名匹配的方法進行引用。這樣,委託就等效於一個型別安全函數指標或一個回調。雖然委託具有許多其他的用途,但這裡只討論委託的事件處理功能。一個委託聲明足以定義一個委託類。聲明提供委託的簽名,公用語言運行庫提供實現。
事件委託是多路廣播的,這意味著它們可以對多個事件處理方法進行引用。委託考慮了事件處理中的靈活性和精確控制。通過維護事件的登入事件處理常式列表,委託為引發事件的類擔當事件發送器的角色。
事件是特殊類型的多路廣播委託,僅可從聲明它們的類或結構(發行者類)中調用。如果其他類或結構訂閱了該事件,則當發行者類引發該事件時,會調用其事件處理常式方法。 EventHandler 委託
EventHandler 委託表示將處理不包含事件數目據的事件的方法。
[SerializableAttribute]
[ComVisibleAttribute(true)]
public delegate void EventHandler (
Object sender,
EventArgs e
)
sender :事件來源。
e :不包含任何事件數目據的 EventArgs。
事件處理常式委託的標準簽名定義一個沒有傳回值的方法,其第一個參數的類型為 Object,它引用引發事件的執行個體,第二個參數從 EventArgs 類型派生,它儲存事件數目據。如果事件不建置事件資料,則第二個參數只是 EventArgs 的一個執行個體。否則,第二個參數為從 EventArgs 派生的自訂類型,提供儲存事件數目據所需的全部欄位或屬性。
EventHandler 是一個預定義的委託,專用於表示不產生資料的事件的事件處理常式方法。如果事件產生資料,則必須提供自己的自訂事件數目據類型,並且必須要麼建立一個委託,其中第二個參數的類型為自訂類型,要麼使用泛型 EventHandler 委託類並用自訂類型替代泛型型別參數。
若要將事件與處理事件的方法關聯,請向事件添加委託的執行個體。除非移除了該委託,否則每當發生該事件時就呼叫事件處理常式。 EventArgs 基類
EventArgs 是包含事件數目據的類的基類。
此類不包含事件數目據,在事件引發時不向事件處理常式傳遞狀態資訊的事件會使用此類。如果事件處理常式需要狀態資訊,則應用程式必須從此類派生一個類來儲存資料。
例如,System.AssemblyLoadEventArgs 類用於儲存程式集載入事件的資料,並包含描述所載入程式集的 System.Reflection.Assembly。
以編程方式訂閱事件
定義一個事件處理常式方法,其簽名與該事件的委託簽名匹配。例如,如果事件基於 EventHandler 委託類型,則下面的代碼錶示方法存根:
void HandleCustomEvent(object sender, CustomEventArgs e)
{
// Do something useful here.
}
使用加法賦值運算子 (+=) 來為事件附加事件處理常式。在下面的樣本中,假設名為 publisher 的對象擁有一個名為 RaiseCustomEvent 的事件。請注意,訂戶類需要引用發行者類才能訂閱其事件。
publisher.RaiseCustomEvent += HandleCustomEvent;
請注意,上面的文法是 C# 2.0 中的新文法。它完全等效於 C# 1.0 文法,必須使用以下新關鍵字顯式建立封裝委託:
publisher.RaiseCustomEvent += new CustomEventHandler(HandleCustomEvent);
使用匿名方法訂閱事件
使用加法賦值運算子 (+=) 來為事件附加匿名方法。在下面的樣本中,假設名為 publisher 的對象擁有一個名為 RaiseCustomEvent 的事件,並且還定義了一個 CustomEventArgs 類以承載某些類型的專用事件資訊。請注意,訂戶類需要引用 publisher 才能訂閱其事件。
publisher.RaiseCustomEvent += delegate(object o, CustomEventArgs e)
{
string s = o.ToString() + " " + e.ToString();
Console.WriteLine(s);
};
請注意,如果您是使用匿名方法訂閱的事件,該事件的取消訂閱過程就比較麻煩。此時要取消訂閱,請返回到該事件的訂閱代碼,將該匿名方法儲存在委託變數中,然後將委託添加到該事件中。
取消訂閱
要防止在引發事件時呼叫事件處理常式,您只需取消訂閱該事件。要防止資源流失,請在釋放訂戶對象之前取消訂閱事件,這一點很重要。在取消訂閱事件之前,在發布對象中作為該事件的基礎的多路廣播委託會引用封裝了訂戶的事件處理常式的委託。只要發布對象包含該引用,就不會對訂戶對象執行記憶體回收。
使用減法賦值運算子 (-=) 取消訂閱事件:
publisher.RaiseCustomEvent -= HandleCustomEvent;
所有訂戶都取消訂閱某事件後,發行者類中的事件執行個體會設定為 null。
自訂事件的實現
以下的內容參考了sam1111的部落格文章,地址為:
http://blog.csdn.net/sam1111/archive/2002/04/15/9773.aspx
C#中的事件處理實際上是一種具有特殊簽名的delegate,像下面這個樣子:
public delegate void MyEventHandler(object sender, MyEventArgs e);
其中的兩個參數,sender代表事件寄件者,e是事件參數類。MyEventArgs類用來包含與事件相關的資料,所有的事件參數類都必須從System.EventArgs類派生。當然,如果你的事件不含參數,那麼可以直接用System.EventArgs類作為參數。
自訂事件的實現可以歸結為以下幾步:
1.定義事件參數類,此類應當從System.EventArgs類派生。如果事件不帶參數,這一步可以省略,可直接轉至步驟3。在發行者類和訂戶類均可看見的範圍中聲明類,並添加保留自訂事件數目據所需的成員。
2.聲明一個委託,它有兩個參數,第一個參數是事件寄件者對象,第二個參數是事件參數類對象。
3. 在發布類中聲明事件。用event關鍵字定義事件對象,它同時也是一個delegate對象。
4. 在發布類中需要觸發事件的地方用調用delegate的方式寫事件觸發方法。一般來說,此方法應為protected訪問限制,既不能以public方式調用,但可以被子類繼承。名字是OnEventName。
5.在訂閱者類中定義事件處理方法,它應當與delegate對象具有相同的參數和傳回值類型。
6.在訂閱者類中用+=操作符添加事件到事件隊列中(-=操作符能夠將事件從隊列中刪除)。
7.在適當的地方呼叫事件觸發方法觸發事件。
下面是一個簡單的例子:
using System;
namespace Event
{
//步驟1,定義事件參數類
public class MyEventArgs : EventArgs
{
private string message;
/// <summary>
/// 資訊
/// </summary>
public string Message
{
get { return message; }
}
//