C#事件處理機制

iDotNetSpace發表於2009-03-04

事件簡介:

   任何進行過圖形使用者介面開發的程式設計人員都會知道事件的概念。當使用者在使用程式的時候,使用者必然要和程式進行一定的互動。比如當使用者點選窗體上的一個按鈕後,程式就會產生該按鈕被點選的事件,並通過相應的事件處理函式來響應使用者的操作。這樣使用者的直觀感覺就是程式執行了我要求的任務了。當然,事件並不一定是在和使用者互動的情況下才會產生的,系統的內部也會產生一些事件並請求處理的,比如時鐘事件就是一個很好例子。不過要介紹C#中的事件處理機制(擴充套件到更廣的範圍便是整個.Net框架),我們首先得明白一個叫"委託"的概念。

C#中的委託:

   委託,顧名思義,就是中間代理人的意思。C#中的委託允許你將一個物件中的方法傳遞給另一個能呼叫該方法的類的某個物件。你可以將類A中的一個方法m(被包含在某個委託中了)傳遞給一個類B,這樣類B就能呼叫類A中的方法m了。同時,你還可以以靜態(static)的方式或是例項(instance)的方式來傳遞該方法。所以這個概念和C++中的以函式指標為引數形式呼叫其他類中的方法的概念是十分類似的。

   委託的概念首先是在Visual J++中被提出來的,現在C#也應用了委託的概念,這也可謂是"拿來主義"吧。C#中的委託是通過繼承System.Delegate中的一個類來實現的,下面是具體的步驟:

   1. 宣告一個委託物件,其引數形式一定要和你想要包含的方法的引數形式一致。

   2. 定義所有你要定義的方法,其引數形式和第一步中宣告的委託物件的引數形式必須相同。

   3. 建立委託物件並將所希望的方法包含在該委託物件中。

   4. 通過委託物件呼叫包含在其中的各個方法。

   以下的C#程式碼顯示瞭如何運用以上的四個步驟來實現委託機制的:

using System;
//步驟1: 宣告一個委託物件
public delegate void MyDelegate(string input);

//步驟2::定義各個方法,其引數形式和步驟1中宣告的委託物件的必須相同
class MyClass1
{
    public void delegateMethod1(string input)
    {
        Console.WriteLine(
            "This is delegateMethod1 and the input to the method is {0}",
            input);
    }
    public void delegateMethod2(string input)
    {
        Console.WriteLine(
            "This is delegateMethod2 and the input to the method is {0}",
            input);
    }
}

//步驟3:建立一個委託物件並將上面的方法包含其中
class MyClass2
{
    public MyDelegate createDelegate()
    {
        MyClass1 c2=new MyClass1();
        MyDelegate d1 = new MyDelegate(c2.delegateMethod1);
        MyDelegate d2 = new MyDelegate(c2.delegateMethod2);
        MyDelegate d3 = d1 + d2;
        return d3;
    }
}

//步驟4:通過委託物件呼叫包含在其中的方法
class MyClass3
{
    public void callDelegate(MyDelegate d,string input)
    {
        d(input);
    }
}
class Driver
{
    static void Main(string[] args)
    {
        MyClass2 c2 = new MyClass2();
        MyDelegate d = c2.createDelegate();
        MyClass3 c3 = new MyClass3();
        c3.callDelegate(d,"Calling the delegate");
    }
}
C#中的事件處理函式:

   C#中的事件處理函式是一個具有特定引數形式的委託物件,其形式如下:

public delegate void MyEventHandler(object sender, MyEventArgs e);
   其中第一個引數(sender)指明瞭觸發該事件的物件,第二個引數(e)包含了在事件處理函式中可以被運用的一些資料。上面的MyEventArgs類是從EventArgs類繼承過來的,後者是一些更廣泛運用的類,如MouseEventArgs類、ListChangedEventArgs類等的基類。對於基於GUI的事件,你可以運用這些更廣泛的、已經被定義好了的類的物件來完成處理;而對於那些基於非GUI的事件,你必須要從EventArgs類派生出自己的類,並將所要包含的資料傳遞給委託物件。下面是一個簡單的例子:
public class MyEventArgs:EventArgs
{
    public string m_id;
}
   在事件處理函式中,你可以通過關鍵字event來引用委託物件,方法如下: public event MyEventHandler MyEvent;
   現在,我們來建立兩個類,通過這兩個類我們可以知道C#完成事件處理的機制是如何工作的。在我們的例項中,A類將提供事件的處理函式,並在步驟3中建立委託物件同時將事件處理函式包含在其中,同上所述,事件處理函式的引數形式必須和委託物件的引數形式相一致。然後,A類將委託物件傳遞給B類。當B類中的事件被觸發後,A類中的事件處理函式就相應的被呼叫了。下面是示例程式碼:
using System;
//步驟1:宣告委託物件
public delegate void MyHandler1(object sender,MyEventArgs e);
public delegate void MyHandler2(object sender,MyEventArgs e);

//步驟2:建立事件處理函式的方法
class A
{
    public const string m_id="Class A";
    public void OnHandler1(object sender,MyEventArgs e)
    {
        Console.WriteLine("I am in OnHandler1 and MyEventArgs is {0}",  e.m_id);
    }
    public void OnHandler2(object sender,MyEventArgs e)
    {
        Console.WriteLine("I am in OnHandler2 and MyEventArgs is {0}",  e.m_id);
    }

    //步驟3:建立委託物件,並事件處理函式包含在其中同時設定好將要觸發事件的物件
    public A(B b)
    {
        MyHandler1 d1=new MyHandler1(OnHandler1);
        MyHandler2 d2=new MyHandler2(OnHandler2);
        b.Event1 +=d1;
        b.Event2 +=d2;
    }
}

//步驟4:通過委託物件(也就是觸發事件)來呼叫被包含的方法
class B
{
    public event MyHandler1 Event1;
    public event MyHandler2 Event2;
    public void FireEvent1(MyEventArgs e)
    {
        if(Event1 != null)
        {
            Event1(this,e);
        }
    }
    public void FireEvent2(MyEventArgs e)
    {
        if(Event2 != null)
        {
            Event2(this,e);
        }
    }
}
public class MyEventArgs:EventArgs
{
    public string m_id;
}
public class Driver
{
    public static void Main()
    {
        B b= new B();
        A a= new A(b);
        MyEventArgs e1=new MyEventArgs();
        MyEventArgs e2=new MyEventArgs();
        e1.m_id ="Event args for event 1";
        e2.m_id ="Event args for event 2";
        b.FireEvent1(e1);
        b.FireEvent2(e2);
    }
}
C#中的GUI的事件處理函式:

   完成GUI下的事件處理函式的基本方法和上面介紹的並沒有什麼多大區別,下面我們就通過上面的方法來完成一個簡單的例項程式。該例項程式的主類MyForm類是從Form類繼承過來的。通過觀察整段程式碼和相關的註解,你可以發現我們並沒有給它宣告委託物件並通過event關鍵字來引用該委託物件,那是因為GUI控制元件早就幫我們做好了該項工作,其委託物件是System.EventHandler。然而,我們還是要為各個控制元件定義方法(也就是事件的處理函式)並將它們包含在建立好的委託物件(System.EventHandler)中。那樣,在使用者和程式進行互動的時候,相應的事件處理函式就會被觸發。具體程式碼如下:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

public class MyForm.:Form
{
    private Button m_nameButton;
    private Button m_clearButton;
    private Label m_nameLabel;

    private Container m_components = null;

    public MyForm()
    {
        initializeComponents();
    }
    private void initializeComponents()
    {
        m_nameLabel=new Label();
        m_nameButton = new Button();
        m_clearButton = new Button();

        SuspendLayout();

        m_nameLabel.Location=new Point(16,16);
        m_nameLabel.Text="Click NAME button, please";
        m_nameLabel.Size=new Size(300,23);

        m_nameButton.Location=new Point(16,120);
        m_nameButton.Size=new Size(176, 23);
        m_nameButton.Text="NAME";
        //建立委託物件,包含方法並將委託物件賦給按鈕的Click事件
        m_nameButton.Click += new System.EventHandler(NameButtonClicked);

        m_clearButton.Location=new Point(16,152);
        m_clearButton.Size=new Size(176,23);
        m_clearButton.Text="CLEAR";
        //建立委託物件,包含方法並將委託物件賦給按鈕的Click事件
        m_clearButton.Click += new System.EventHandler(ClearButtonClicked);

        this.ClientSize = new Size(292, 271);
        this.Controls.AddRange(new Control[] {m_nameLabel,
                                              m_nameButton,
                                              m_clearButton});
        this.ResumeLayout(false);
    }
    //定義方法(事件的處理函式),其引數形式必須和委託物件的一致
    private void NameButtonClicked(object sender, EventArgs e)
    {
        m_nameLabel.Text = "My name is john, please click CLEAR button to clear it";
    }
    private void ClearButtonClicked(object sender,EventArgs e)
    {
        m_nameLabel.Text = "Click NAME button, please";
    }
    public static void Main()
    {
        Application.Run(new MyForm());
    }
}

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-561368/,如需轉載,請註明出處,否則將追究法律責任。

相關文章