事件(event),這個詞兒對于初學者來說,往往總是顯得有些神秘,不易弄懂。而這些東西卻往往又是程式設計中常用且非常重要的東西。大家都知道windows消息處理機制的重要,其實C#事件就是基于windows消息處理機制的,隻是封裝的更好,讓開發者無須知道底層的消息處理機制,就可以開發出強大的基于事件的應用程式來。
先來看看事件程式設計有哪些好處。
在以往我們編寫這類程式中,往往采用等待機制,為了等待某件事情的發生,需要不斷地檢測某些判斷變量,而引入事件程式設計後,大大簡化了這種過程:
- 使用事件,可以很友善地确定程式執行順序。
- 當事件驅動程式等待事件時,它不占用很多資源。事件驅動程式與過程式程式最大的不同就在于,程式不再不停地檢查輸入裝置,而是呆着不動,等待消息的到來,每個輸入的消息會被排進隊列,等待程式處理它。如果沒有消息在等待,則程式會把控制交回給作業系統,以運作其他程式。
- 事件簡化了程式設計。作業系統隻是簡單地将消息傳送給對象,由對象的事件驅動程式确定事件的處理方法。作業系統不必知道程式的内部工作機制,隻是需要知道如何與對象進行對話,也就是如何傳遞消息。
有了這麼多好處,看來我們的确有必要掌握它。俗話說:“難了不會,會了不難”。就讓我們一步一步開始吧...
要講事件,必然要講到委托(delegate)。它們之間的關系可以通過一個淺顯的比方來說明,這個比方可能不是十分恰當。比如你要租一個房屋,這是一個事件,那麼委托就是房屋租賃中介,當你把租房子的消息告知中介後,中介就會産生出一套符合你要求的房屋租賃方案來。再由中介執行這套方案,你便租得了這個房屋,即事件被處理了。當然你也可以不通過中介,直接找房東,但如果沒有網際網路等工具,你如何得到誰出租房屋的資訊?話題扯遠了。
委托(delegate)
委托可以了解成為函數指針,不同的是委托是面向對象,而且是類型安全的。關于委托的了解,可以參考我的另一篇文章《C#委托之個人了解》。
事件(event)
我們可以把事件程式設計簡單地分成兩個部分:事件發生的類(書面上叫事件發生器)和事件接收處理的類。事件發生的類就是說在這個類中觸發了一個事件,但這個類并不知道哪個個對象或方法将會加收到并處理它觸發的事件。所需要的是在發送方和接收方之間存在一個媒介。這個媒介在.NET Framework中就是委托(delegate)。在事件接收處理的類中,我們需要有一個處理事件的方法。好了,我們就按照這個順序來實作一個捕獲鍵盤按鍵的程式,來一步一步說明如何編寫事件應用程式。
1、首先建立一個自己的EventArgs類。
引自MSDN:
EventArgs是包含事件資料的類的基類,此類不包含事件資料,在事件引發時不向事件處理程式傳遞狀态資訊的事件會使用此類。如果事件處理程式需要狀态資訊,則應用程式必須從此類派生一個類來儲存資料。
因為在我們鍵盤按鍵事件中要包含按鍵資訊,是以要派生一個KeyEventArgs類,來儲存按鍵資訊,好讓後面知道按了哪個鍵。
class KeyEventArgs : EventArgs //按鍵資訊
{
private char keyChar;
public KeyEventArgs(char keyChar)
: base()
{
this.keyChar = keyChar;
}
public char KeyChar
{
get { return keyChar; }
}
}
2、再建立一個事件發生的類KeyInputMonitor,這個類用于監控鍵盤按鍵的輸入并觸發一個事件:
//建立一個委托,傳回類型void,兩個參數
public delegate void KeyDownEventHandler(object sender, KeyEventArgs e);
//事件發生方
class KeyInputMonitor
{
//定義事件
public event KeyDownEventHandler KeyDown;
public void Run()
{
bool finished = false;
do
{
Console.WriteLine("Input a char");
string response = Console.ReadLine();
char responseChar = (response == "") ? ' ' : char.ToUpper(response[0]);
switch (responseChar)
{
case 'X':
finished = true;
break;
default:
//得到按鍵資訊的參數
KeyEventArgs keyEventArgs = new KeyEventArgs(responseChar);
//觸發事件
KeyDown(this, keyEventArgs);
break;
}
} while (!finished);
}
}
這裡注意KeyDown( this, KeyEventArgs );一句,這就是觸發事件的語句,并将事件交由KeyDown這個委托來處理,委托指定事件處理方法去處理事件,這就是事件接收方的類的事情了。參數this是指觸發事件的對象就是本身這個對象,keyEventArgs包含了按鍵資訊。
3、最後建立一個事件接收方的類,這個類先産生一個委托執行個體,再把這個委托執行個體添加到産生事件對象的事件清單中去,這個過程又叫訂閱事件。然後提供一個方法回顯按鍵資訊。
//事件接收方
class EventReceiver
{
public EventReceiver(KeyInputMonitor monitor)
{
//産生一個委托執行個體并添加到KeyInputMonitor産生的事件清單中
monitor.KeyDown += new KeyDownEventHandler(this.Echo);
}
//事件處理函數
private void Echo(object sender, KeyEventArgs e)
{
Console.WriteLine("Capture key:{0}", e.KeyChar);
}
}
4、看一下如何調用
//主程式運作
class MainEntryPoint
{
static void Main()
{
//執行個體化一個事件發送方
KeyInputMonitor monitor = new KeyInputMonitor();
//執行個體化一個事件接收方
EventReceiver eventReceiver = new EventReceiver(monitor);
//運作
monitor.Run();
}
}
總結:
C#中使用事件需要的步驟:
1.建立一個委托
2.将建立的委托與特定事件關聯(.Net類庫中的很多事件都是已經定制好的,是以他們也就有相應的一個委托,在編寫關聯事件處理程式--也就是當有事件發生時我們要執行的方法的時候我們需要和這個委托有相同的簽名)
3.編寫事件處理程式
4.利用編寫的事件處理程式生成一個委托執行個體
5.把這個委托執行個體添加到産生事件對象的事件清單中去,這個過程又叫訂閱事件
C#中事件産生和實作的流程:
1.定義A為産生事件的執行個體,a為A産生的一個事件
2.定義B為接收事件的執行個體,b為處理事件的方法
3.A由于使用者(程式編寫者或程式使用者)或者系統産生一個a事件(例如點選一個Button,産生一個Click事件)
4.A通過事件清單中的委托對象将這個事件通知給B
5.B接到一個事件通知(實際是B.b利用委托來實作事件的接收)
6.調用B.b方法完成事件處理