浅谈Winform事件的实现以及模拟其事件的实现(附实现源码)
当我们初学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