您的位置:首页 - 教程 - WinForm - 正文
浅谈Winform事件的实现以及模拟其事件的实现

当我们初学Winform的时候被其神奇的事件功能所吸引,当点击一个按钮时,便会跳到我们所写的点击方法当中去。然而这并不符合我们对方法的理解,究竟.net在后面帮助我们实现了什么。我们怎样模拟其事件的实现呢。下面先从ButtonClick方法说起。

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反编译一下,这是对鼠标事件的判定,我们会惊奇的发现里面有对单击与双击的判定。




在往下走便是对鼠标事件的监听,有兴趣可以继续往下查看调用堆栈,


我们总结一下,buttonclick的触发经过如下过程

好了到目前为止我们已经对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(1
00); } } }

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













评论: