當我們初學Winform的時候被其神奇的事件功能所吸引,當點擊一個按鈕時,便會跳到我們所寫的點擊方法當中去。然而這並不符合我們對方法的理解,究竟.net在后面幫助我們實現了什么。我們怎樣模擬其事件的實現呢。下面先從Button的Click方法說起。
1.首先查看設計器自動生成的代碼
partial class Form1 { #region Windows 窗體設計器生成的代碼 /// <summary> /// 設計器支持所需的方法 - 不要 /// 使用代碼編輯器修改此方法的內容。 /// </summary> private void InitializeComponent() { //實例化一個按鈕 this.button1 = new System.Windows.Forms.Button(); this.SuspendLayout(); // // button1 // this.button1.Location = new System.Drawing.Point(491, 100); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(75, 23); this.button1.TabIndex = 0; this.button1.Text = "button1"; this.button1.UseVisualStyleBackColor = true; //添加點擊事件 this.button1.Click += new System.EventHandler(this.button1_Click); } #endregion private System.Windows.Forms.Button button1; }
我們發現了對事件的添加 this.button1.Click += new System.EventHandler(this.button1_Click);
this.button1.Click中的Click是什么呢?我們F12轉到定義看一下(注意:Button繼承自Control(所有控件父類))

我們發現event,Click是一個事件,然后我們反編譯看一下(可以看到+=,-=的實現)

EventHandler轉到定義sender事件源(就是被誰引發的),e(事件數據)
到目前為止this.button1.Click添加了事件,但是我們知道了事件,button1訂閱了這個事件,但是事件如何觸發的呢?我們進行調試,在調用堆棧中觀察,如圖
我們從上而下進行逆向分析
01.System.Windows.Forms.dll!System.Windows.Forms.Control.OnClick(System.EventArgs e) + 0x62 字節,我們對
System.Windows.Forms.Control.OnClick反編譯一下,handler不為空說明事件被訂閱,執行
private void button1_Click(object sender, EventArgs e){}

02System.Windows.Forms.dll!System.Windows.Forms.Button.OnClick(System.EventArgs e) + 0x80 字節我們對
System.Windows.Forms.Button.OnClick反編譯一下,調用01的方法

03System.Windows.Forms.dll!System.Windows.Forms.Button.OnMouseUp(System.Windows.Forms.MouseEventArgs
mevent = {X = 36 Y = 13 Button = Left}) + 0xac 字節,我們對System.Windows.Forms.Button.OnMouseUp反編譯一下,
該方法最后調用Control.OnMouseUp方法執行鼠標彈起的事件


04System.Windows.Forms.dll!System.Windows.Forms.Control.WmMouseUp(ref System.Windows.Forms.Message m, System.Windows.Forms.MouseButtons button, int clicks) + 0x274 字節我們對System.Windows.Forms.Control.WmMouseUp反編譯一下,這是對鼠標事件的判定,我們會驚奇的發現里面有對單擊與雙擊的判定。

在往下走便是對鼠標事件的監聽,有興趣可以繼續往下查看調用堆棧,
我們總結一下,button的click的觸發經過如下過程
好了到目前為止我們已經對Winform事件有了一定的了解,那我們如何借助這個思想來實現我們自己的事件處理呢?
接下來我們模擬一個場景,我們有一個文本文件,我們監聽文件,如果文本文件發生改變(相當於上面所說的鼠標監聽觸發事件),觸發事件向管理員和用戶發一條信息提示(這里的人相當於button對象,向不同人發模擬Winform不同控件的click事件)。利用剛才的Winform事件技術實現一下;
1首先定義一個事件的委托
//處理文件發生變化后的委托聲明 public delegate void MonitorEventHandler(object sender, EventArgs e);
2事件傳遞的事件數據
//事件數據類 繼承自EventArgs public class MsgEventArgs : EventArgs { /// <summary> /// /// </summary> /// <param name="changeTime">修改時間</param> /// <param name="toSend">提示信息</param> public MsgEventArgs(DateTime changeTime, string toSend) { this.ChangeTime = changeTime; this.ToSend = toSend; } // 修改時間 public DateTime ChangeTime { get; set; } // 提示信息 public string ToSend { get; set; } }
3 MonitorText類監控文件類(相當於上面講的鼠標監聽類)
public class MonitorText { //定義監控文本事件 public event MonitorEventHandler MonitorEvent; //上次文件更新時間用於判斷文件是否修改過 private DateTime _lastWriteTime = File.GetLastWriteTime(@"C:\Users\HHY\Desktop\1.txt"); public MonitorText() { } // 文件更新調用 protected virtual void OnTextChange(MsgEventArgs e) { if (MonitorEvent != null) { //不為空,處理事件 MonitorEvent(this, e); } } //事件監聽的方法 public void BeginMonitor() { DateTime bCurrentTime; while (true) { bCurrentTime = File.GetLastWriteTime(@"C:\Users\HHY\Desktop\1.txt"); if (bCurrentTime != _lastWriteTime) { _lastWriteTime = bCurrentTime; MsgEventArgs msg = new MsgEventArgs(bCurrentTime,"文本改變了"); OnTextChange(msg); }
//0.1秒監控一次 Thread.Sleep(100); } } }
4管理員類(相對於Button類)
public class Administrator { //管理員事件處理方法 public void OnTextChange(object Sender, EventArgs e) { Console.WriteLine("尊敬的管理員:"+DateTime.Now.ToString() + ": 文件發生改變."); } }
5用戶類(相對於Button類以外的控件類)
public class User { //用戶事件處理方法 public void OnTextChange(object Sender, EventArgs e) { Console.WriteLine("尊敬的用戶:" + DateTime.Now.ToString() + ": 文件發生改變."); } }
6程序的Main方法
class Program { //定義監控文本對象 static MonitorText MonitorTextEventSource; static void Main(string[] args) { MonitorTextEventSource = new MonitorText(); //1. 啟動后台線程添加監視事件 var thrd = new Thread(MonitorTextEventSource.BeginMonitor); thrd.IsBackground = true; thrd.Start(); //2實例化管理員類 Administrator ad = new Administrator(); //3實例化用戶類 User user = new User(); //4訂閱事件 MonitorTextEventSource.MonitorEvent += ad.OnTextChange; MonitorTextEventSource.MonitorEvent += user.OnTextChange; Console.ReadLine(); } }
運行程序
好了到現在,我們的模擬完成了,大體將Winform事件的流程實現了一遍,由於自己本身也也是一個小白理解的不到位的地方請大家指出來,我把程序源碼放在了下面,大家可以調試運行一下。
源碼地址:http://pan.baidu.com/s/1bRelEQ