摘要:[C#] 事件
Introduction
事件本身代表某種動作被執行,例如 button 被使用者按下,textbox 輸入文字..等
事件由類別所產生,其他物件或方法處理器因此被通知處理所觸發的事件,而其間的
關聯則透過委派物件來完成。
撰寫事件處理程式步驟如下:
- 宣告委派型別
 - 定義 System.EventArgs 類別的衍生類別,儲存事件相關資訊
 - 使用關鍵字 Event 宣告事件
 - 定義事件處理程式之方法成員
 - 使用委派物件封裝方法成員
 - 引用委派方法處理觸發事件
 
其中建立事件的語法:
- event delegateName eventObject
 
event : 關鍵字
eventObject : 事件變數
delegateName : 支援此事件的委派名稱
Example
sample1
非標準版本
using System;
//宣告一個委派型別:無回傳值,無任何參數。
delegate void DlgDoCalcDelegate() ;
class calc {
    //宣告一個由 DlgDoCalcDelegate 委派所支援的事件
    public event DlgDoCalcDelegate evtDoCalc;
    //定義觸發此事件的方法
    public void DoCalc() {
        evtDoCalc();
    }
}
class EventsHandler
{
    //定義事件處理程式方法成員
	private  void DoAdd() 
	{
		AddMethod() ; 
	}	
    
	private void AddMethod() 
	{
		long lngFirstValue ; 
		long lngSecondValue ;	
		long lngSum ; 
		Console.WriteLine ("請輸入第一個進行運算數值 :") ; 
		lngFirstValue = long.Parse(Console.ReadLine()) ; 
		Console.WriteLine ("請輸入第二個進行運算數值 :") ;
		lngSecondValue =  long.Parse(Console.ReadLine()) ;
        lngSum = lngFirstValue + lngSecondValue; 
		Console.WriteLine
			("{0} 與 {1} 的加總等於 {2} " , lngFirstValue,lngSecondValue,lngSum) ; 
	}
	
	static void Main()
	{
		EventsHandler myEventsHandler = new EventsHandler() ; 
		calc mycalc =  new calc() ; 
        //將 DoAdd 方法於 evtDoCalc 事件中註冊
		mycalc.evtDoCalc += new DlgDoCalcDelegate(myEventsHandler.DoAdd) ; 
		Console.WriteLine ("觸發加法運算事件 …") ;
        //觸發事件。
		mycalc.DoCalc() ; 	
		Console.Read() ; 
	}
}
執行結果
sample2
上面範例所示,我可以自訂任何方法支援觸發事件,然而,這不是最好的,
最好是符合 .net 事件處理方法的準則。以下我們觀察表單事件。
public Form1() {
            InitializeComponent();
            //訂閱表單 Click 事件
            this.Click += new EventHandler(Form1_Click);
        }
        //當表單事件被觸發後,會執行這個 Method
        void Form1_Click(object sender, EventArgs e) {
            //Do Something
        }
其中
sender : 代表觸發此事件的來源物件
e : 則包含了事件相關資訊的 EventArgs 類別物件,是其他事件類別的基底類別
reference :http://msdn.microsoft.com/zh-tw/library/ms229011%28VS.80%29.aspx
標準版本
using System;
//定義 SpeedCheckEventArgs 繼承 EventArgs
public class SpeedCheckEventArgs : EventArgs {
    //撰寫該事件相關資訊
    private long speed;
    public SpeedCheckEventArgs(long speed) {
        this.speed = speed;
    }
    public long getSpeed {
        get { return speed; }
    }
    public string WarningMessage {
        get {
            return ("警告 : 行車超過速限 !!");
        }
    }
}
//定義委派型別,沒有回傳值,並且需要兩個參數傳入
public delegate void SpeedCheckHandler(object sender, SpeedCheckEventArgs e);
public class CheckSpeed {
    //定義符合 SpeedCheckHandler 委派的事件
    public event SpeedCheckHandler myEvent;
    public void CheckSpeedLimit(long speed) {
        if (speed > 60) {
            //建立 SpeedCheckEventArgs 物件。
            SpeedCheckEventArgs speedsArgs = new SpeedCheckEventArgs(speed);
            //觸發事件,傳入來源物件與事件物件。
            myEvent(this, speedsArgs);
        } else {
            Console.WriteLine("您目前的速度正常");
        }
    }
}
public class DoSomeThing {
    //定義 SlowDown 方法,傳入兩個參數,其中 e 為 SpeedCheckEventArgs 型別。
    public void SlowDown(object sender, SpeedCheckEventArgs e) {
        Console.WriteLine
            (e.WarningMessage);
        Console.WriteLine("您目前車速 {0} 已超速,請踩下煞車,降低速度,避免危險 !!", e.getSpeed);
        Console.WriteLine
            ("正常行車速度請降至 60 Km/hr 以下 !!");
    }
}
//主程式
public class Events {
    static void Main() {
        long speed;
        CheckSpeed myCheckSpeed = new CheckSpeed();
        DoSomeThing myDoSomeThing = new DoSomeThing();
        Console.Write("目前行車速度 : ");
        //取得使用者輸入數字
        speed = long.Parse(Console.ReadLine());
        Console.WriteLine("");
        //訂閱事件。
        myCheckSpeed.myEvent += new SpeedCheckHandler(myDoSomeThing.SlowDown);
        //檢查車速
        myCheckSpeed.CheckSpeedLimit(speed);
        Console.ReadLine();
    }
}
執行結果
sample3
若是事件處理過程,不需使用 EventArg 引數傳遞事件所包含的資訊,可以考慮直接使用 EventHandler 這個
.net 預設的委派型別。
    //定義一個計算類別
    class calc {
        //建立一個內鍵事件
        public event EventHandler evtDoCalc;
        //觸發事件
        public void DoCalc() {
            evtDoCalc(this, EventArgs.Empty);
        }
    }
    //主程式
    class Program {
        static void Main(string[] args) {
            Program myEventsHandler = new Program();
            calc mycalc = new calc();
            //繫結事件
            mycalc.evtDoCalc += new EventHandler(myEventsHandler.DoAdd);
            Console.WriteLine("觸發加法運算事件…");
            //開始做計算
            mycalc.DoCalc();
            Console.Read();
        }
        private void DoAdd(object o, EventArgs e) {
            Console.WriteLine("觸發事件的來源物件 : {0} \n", o.ToString());
            AddMethod();
        }
        //加法函式
        private void AddMethod() {
            long lngFirstValue;
            long lngSecondValue;
            long lngSum;
            Console.WriteLine("請輸入第一個進行運算數值 :");
            lngFirstValue = long.Parse(Console.ReadLine());
            Console.WriteLine("請輸入第二個進行運算數值 :");
            lngSecondValue = long.Parse(Console.ReadLine());
            lngSum = lngFirstValue + lngSecondValue;
            Console.WriteLine
                ("{0} 與 {1} 的加總等於 {2} ", lngFirstValue, lngSecondValue, lngSum);
        }
    }
}執行結果
sample4
多重事件
//定義委派型別
delegate void MultiCastDel(int intx, int inty);
//加法類別
class AddCalc {
    public void DoAdd(int intx, int inty) {
        int intResult;
        intResult = intx + inty;
        Console.WriteLine("物件 AddCalc 對兩個整數 {0},{1} 作加法運算 !!",
intx, inty);
        Console.WriteLine("執行運算結果等於 {0} \n", intResult);
    }
}
//減法類別
class SubCalc {
    public void DoSub(int intx, int inty) {
        int intResult;
        intResult = intx - inty;
        Console.WriteLine("物件 SubCalc 對兩個整數 {0},{1} 作減法運算 !!"
, intx, inty);
        Console.WriteLine("執行運算結果等於 {0} \n", intResult);
    }
}
//乘法類別
class MultiCalc {
    public void DoMul(int intx, int inty) {
        int intResult;
        intResult = intx * inty;
        Console.WriteLine("物件 MultiCalc 對兩個整數 {0},{1} 作乘法運算 !!", intx, inty);
        Console.WriteLine("執行運算結果等於 {0} \n", intResult);
    }
}
//除法類別
class DivCalc {
    public void DoDiv(int intx, int inty) {
        if (inty == 0) {
            Console.WriteLine("除數為 0 無法作除法運算 !!");
        } else {
            int intResult;
            intResult = intx / inty;
            Console.WriteLine("物件 DivCalc 對兩個整數 {0},{1} 作除法運算 !!", intx, inty);
            Console.WriteLine("執行運算結果等於 {0} \n", intResult);
        }
    }
}
//事件類別
class MultiEvent {
    int x;
    int y;
    public int px {
        set {
            x = value;
        }
    }
    public int py {
        set {
            y = value;
        }
    }
    //建立事件並且支援 MultiCastDel 委派
    public event MultiCastDel DoEvent;
    public void OnDoEvent() {
        DoEvent(x, y);
    }
}
//主程式
class MultiCastEvent {
    static void Main() {
        AddCalc myAddCalc = new AddCalc();
        SubCalc mySubCalc = new SubCalc();
        MultiCalc myMultiCalc = new MultiCalc();
        DivCalc myDivCalc = new DivCalc();
        MultiEvent myMultiEvent = new MultiEvent();
        myMultiEvent.px = 100;
        myMultiEvent.py = 100;
        myMultiEvent.DoEvent += new MultiCastDel(myAddCalc.DoAdd);
        myMultiEvent.DoEvent += new MultiCastDel(mySubCalc.DoSub);
        myMultiEvent.DoEvent += new MultiCastDel(myMultiCalc.DoMul);
        myMultiEvent.DoEvent += new MultiCastDel(myDivCalc.DoDiv);
        myMultiEvent.OnDoEvent();
        Console.ReadLine();
    }
}
執行結果
- delegate (C# 參考)
 - http://www.dotblogs.com.tw/atowngit/archive/2009/12/07/12311.aspx
 - event (C# 參考)
 - HOW TO:訂閱及取消訂閱事件 (C# 程式設計手冊)
 - EventHandler 委派
 - EventArgs 類別
 - HOW TO:在衍生類別中引發基底類別事件 (C# 程式設計手冊)
 - HOW TO:發行符合 .NET Framework 方針的事件 (C# 程式設計手冊)
 - 事件設計
 - HOW TO:實作介面事件 (C# 程式設計手冊)
 - HOW TO:使用字典儲存事件執行個體 (C# 程式設計手冊)
 - 事件範例
 
三小俠 小弟獻醜,歡迎指教


