關於委託的使用最好是通過執行個體,掌握了某種模式之後就會逐漸理解其工作的原理了。下面我寫一段簡單的通過定義事件的代碼:(建議將代碼拷貝到VS2005中再看會更清晰一點)
/// <summary>
/// 聲明一個TextChanged委託,該委託有一個TextChangedEventArgs類型的參數作為資料的傳遞。
/// </summary>
/// <param name="e"></param>
public delegate void TextChangedHandler(TextChangedEventArgs e);
public partial class Form1 : Form
{
/// <summary>
/// 定義一個TextChanged類型的事件。
/// </summary>
public event TextChangedHandler TextChanged;
private string m_Text;
/// <summary>
/// Text屬性
/// </summary>
public string Text
{
get { return m_Text; }
set
{
m_Text = value;
// 當前類的m_Text被修改的時候發布TextChanged事件。
OnTextChanged(m_Text);
}
}
/// <summary>
/// 發布TextChanged事件。
/// </summary>
/// <param name="text"></param>
private void OnTextChanged(string text)
{
if (TextChanged != null)
{
TextChanged(new TextChangedEventArgs(text));
}
}
public Form1()
{
InitializeComponent();
this.TextChanged += new TextChanged(Form1_TextChanged);
}
/// <summary>
/// 當發生了TextChanged事件之後的處理方法。
/// </summary>
/// <param name="e"></param>
void Form1_TextChanged(TextChangedEventArgs e)
{
MessageBox.Show(e.Text);
}
}
public class TextChangedEventArgs:EventArgs
{
private string m_Text;
public string Text
{
get{return m_Text;}
}
public TextChangedEventArgs(string text)
{
m_Text = text ;
}
}
上面的這個類是一個簡單的WinForm下的Form視窗對象。在該類前面聲明了一個TextChanged委託。其實委託就是一個回呼函數的格式定義。下面我來解釋一下上面這段代碼的工作方式。
上面這段代碼是微軟程式種最標準的事件聲明和發布的方式。在所有微軟的控制項中到處充斥這這種代碼,如果你可以反編譯微軟的代碼的話,你會看到非常非常多的On.....方法,這種以On開頭的方法都是發布事件以及內部事件處理的方法。
那麼怎樣聲明一個事件呢?這要看你要用這個事件做什麼了,通常情況下我們使用事件發布我們當前對象的某個狀態被改變了,已通知那些對這個狀態感興趣的對象。如果沒有什麼需要傳遞的資訊,那麼這種事件可以直接才採用微軟提供的最簡單的委託來聲明這個事件——EventHandler.一般情況下微軟的委託都是以Handler為尾碼的,用來區分方法名所用,而且也可以生動的告訴使用者一個委託就是一個控制代碼一個指標並非一個實體。上面的代碼中“public event TextChangedHandler TextChanged;”就是用我們自己定義的TextChangedHandler委託聲明的事件。
那麼這個事件怎麼使用呢?我們聲明了不去用那麼也是白費。我們的目的是在Form1的Text屬性被更改的時候,即時的通知某些關心這個屬性的對象,因此我們就要在Form1的Text的屬性的Set方法中寫下一個
set
{
m_Text = value;
// 當前類的m_Text被修改的時候發布TextChanged事件。
OnTextChanged(m_Text);
}
當程式通過Text的Set方法為Text賦值之後,就會調用一個OnTextChanged()方法,並通過參數形式將改變之後的Text值傳遞給這個方法。而這個OnTextChanged方法就會檢測當前對象的TextChanged事件是否有被註冊的。if (TextChanged != null),這個判斷就是判斷是否有對象註冊了這個事件。註:當有對象通過+=的形式註冊了事件則事件TextChanged就不等於空了。上利中this.TextChanged += new TextChanged(Form1_TextChanged)已經註冊了這個事件,因此在OnTextChanged方法中的判斷是成立的,所以代碼TextChanged(new TextChangedEventArgs(text));將會被調用。這裡看起來好像很奇怪,怎麼TextChanged事件變成了一個方法,別忘了我們是用TextChangedHandler這個代理聲明的這個事件,因此這個事件的形式就會和TextChangedHandler的格式一樣。
在這裡TextChanged(new TextChangedEventArgs(text));做的事情類似於一個迴圈,他會找到所有已經註冊這個事件的方法,也就是上例中
/// <summary>
/// 當發生了TextChanged事件之後的處理方法。
/// </summary>
/// <param name="e"></param>
void Form1_TextChanged(TextChangedEventArgs e)
{
MessageBox.Show(e.Text);
}
只要註冊了這個事件並具有這種方法的對象,都將被調用。這也也就是為什麼將委託叫回呼函數的原因。這樣每個關注Form1.Text屬性的對象都可以有自己的處理方式,待發生了這個事件之後,有事件發行者去調用這些已經定義好的操作。這樣就充分達到低耦合度的目的。
至於上例中所定義public class TextChangedEventArgs:EventArgs
類,直接繼承自系統的EventArgs類,作用於系統的EventArgs類一樣都只是在事件發生的時候用來傳遞事件數目據的用的。當然這隻是微軟內部關於事件數目據的一種約定,我們在代理中也可以傳遞其他形式的類的對象,不過應盡量使用微軟的這種形式來傳遞事件數目據,這樣也有利於改善程式的可讀性。我們可以利用這種形式定義一些更加複雜的資料在事件發生時進行傳遞。這樣就可以更加靈活的使用事件來進行對象之間的交流了。
上面的解釋是我個人對委託的理解,如有不正確的地方還請高手指正。對於提問者我想我這種事件的處理方式對於你來說已經非常合適,因為我在開發過程中經常用這種模式來定義事件,這樣我的程式靈活性加大了很多,而且這也是微軟奉行的模式,總會有他的道理的。希望對你有所協助。(以上例子以及說明完全由我個人所寫沒有拷貝任何參考資料)