这也是今天讨论到的一个话题,其实还是比较简单的。因为事件处理程序都是在主线程被执行的,所以主线程肯定是依次执行他们。那么究竟是什么决定了这个顺序呢?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;using System.Threading;
namespace ConsoleApplication1
{class Program{static void Main(string[] args){///这个例子解释了如果为一个事件绑定了多个事件处理程序,那么他们处理的顺序与绑定顺序是一致的Console.WriteLine("主线程号是:{0}", Thread.CurrentThread.ManagedThreadId);Employee e = new Employee();e.NameChanged += new EventHandler(e_NameChanged);e.NameChanged += new EventHandler(e_NameChanged2);e.Name = "ares chen";Console.Read();}static void e_NameChanged2(object sender, EventArgs e){Console.WriteLine("第2个事件处理程序触发的时间是:{0}", DateTime.Now);Console.WriteLine("当前线程号是:{0}", Thread.CurrentThread.ManagedThreadId);}static void e_NameChanged(object sender, EventArgs e){Console.WriteLine("第1个事件处理程序触发的时间是:{0}", DateTime.Now);Console.WriteLine("当前线程号是:{0}", Thread.CurrentThread.ManagedThreadId);            }}class Employee{public event EventHandler NameChanged;private string name;public string Name{get{return name;}set{name = value;if (NameChanged != null)NameChanged(this, null);}}}
}

其实要深入看的话,这是因为事件的处理程序是通过一个列表来管理的,就是EventHandlerList


[HostProtection(SecurityAction.LinkDemand, SharedState=true)]
public sealed class EventHandlerList : IDisposable
{// Fieldsprivate ListEntry head;private Component parent;// Methodspublic EventHandlerList(){}internal EventHandlerList(Component parent){this.parent = parent;}public void AddHandler(object key, Delegate value){ListEntry entry = this.Find(key);if (entry != null){entry.handler = (entry.handler, value);//这里的关键在于Delegate.Combine,所以根据注册顺序不一样,是一个顺序型的组合}else{this.head = new ListEntry(key, value, this.head);}}public void AddHandlers(EventHandlerList listToAddFrom){for (ListEntry entry = listToAddFrom.head; entry != null; entry = entry.next){this.AddHandler(entry.key, entry.handler);}}public void Dispose(){this.head = null;}private ListEntry Find(object key){ListEntry head = this.head;while (head != null){if (head.key == key){return head;}head = head.next;}return head;}public void RemoveHandler(object key, Delegate value){ListEntry entry = this.Find(key);if (entry != null){entry.handler = Delegate.Remove(entry.handler, value);}}// Propertiespublic Delegate this[object key]{get{ListEntry entry = null;if ((this.parent == null) || this.parent.CanRaiseEventsInternal){entry = this.Find(key);}if (entry != null){return entry.handler;}return null;}set{ListEntry entry = this.Find(key);if (entry != null){entry.handler = value;}else{this.head = new ListEntry(key, value, this.head);}}}// Nested Typesprivate sealed class ListEntry{// Fieldsinternal Delegate handler;internal object key;internal EventHandlerList.ListEntry next;// Methodspublic ListEntry(object key, Delegate handler, EventHandlerList.ListEntry next){this.next = next;this.key = key;this.handler = handler;}}
}所以,既然是通过线性表来保存的,那么就有一个先后顺序的情况。其实,一个更好的写法是下面这样的
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;using System.Threading;
using System.ComponentModel;
namespace ConsoleApplication1
{class Program{static void Main(string[] args){///这个例子解释了如果为一个事件绑定了多个事件处理程序,那么他们处理的顺序与绑定顺序是一致的Console.WriteLine("主线程号是:{0}", Thread.CurrentThread.ManagedThreadId);Employee e = new Employee();e.NameChanged += new EventHandler(e_NameChanged);e.NameChanged += new EventHandler(e_NameChanged2);e.Name = "ares chen";Console.Read();}static void e_NameChanged2(object sender, EventArgs e){Console.WriteLine("第2个事件处理程序触发的时间是:{0}", DateTime.Now);Console.WriteLine("当前线程号是:{0}", Thread.CurrentThread.ManagedThreadId);}static void e_NameChanged(object sender, EventArgs e){Console.WriteLine("第1个事件处理程序触发的时间是:{0}", DateTime.Now);Console.WriteLine("当前线程号是:{0}", Thread.CurrentThread.ManagedThreadId);            }}class Employee{//public event EventHandler NameChanged;private string name;public string Name{get{return name;}set{name = value;}}}
}

为什么使用EventHandlerList? 这个问题之前就谈论过,默认情况下,客户端程序每为事件绑定一个处理程序,就需要在类型中产生一个delegate的引用,如此一来,如果事件很多的话,不利于较好地控制内存。但如果用EventHandlerList的话,则有利于统一管理所有的delegate

事件处理程序的处理顺序问题相关推荐

  1. angular五大服务顺序,angularJS $事件处理程序的触发顺序

    I was wondering two things, in the context of angularJS event handling. How is defined the order in ...

  2. 后处理程序文件大小的变量_【每日一题】(17题)面试官问:JS中事件流,事件处理程序,事件对象的理解?...

    关注「松宝写代码」,精选好文,每日一题 作者:saucxs | songEagle 2020,实「鼠」不易 2021,「牛」转乾坤 风劲潮涌当扬帆,任重道远须奋蹄! 一.前言 2020.12.23 立 ...

  3. javaScript事件(二)事件处理程序

    一.事件 二.事件流 以上内容见:javaScript事件(一)事件流 三.事件处理程序 前面提到,事件是用户或浏览器自身执行的某种动作,如click,load和mouseover都是事件的名字.响应 ...

  4. 事件(二):事件处理程序

    click,load,mouseover都是事件的名字,而响应某个事件的函数就叫做事件处理程序(或事件侦听器).事件处理程序的名字以'on'开头,onclick,onload 事件处理程序(html事 ...

  5. 读《Javascript高级程序设计》中的javascript事件处理程序(事件侦听器)心得

    今天读了<Javascript高级程序设计>中的javascript事件处理程序(事件侦听器)部分的内容,总结一些自己的心得: 事件就是用户或者浏览器自身执行的某种动作.例如click . ...

  6. JavaScript事件处理程序的3种方式

    最近这段时间因为每天要修改网站,为网站做特效,所以看了很多的js接触事件,自己只会使用一小部分,有时用的时候也比较混乱,现在系统的整理了一下,首先跟大家在马海祥博客上跟大家分享的是JavaScript ...

  7. button添加插槽之后绑定不来事件_javaScript基础事件(二)事件处理程序

    前面提到,事件是用户或浏览器自身执行的某种动作,如click,load和mouseover都是事件的名字.响应某个事件的函数就叫事件处理程序(也叫事件处理函数.事件句柄).事件处理程序的名字以&quo ...

  8. 同一个按钮绑定多个事件_带你走进JavaScript世界系列——事件处理程序之 IE 事件处理...

    IE 事件处理程序 IE 实现了与 DOM 中类似的两个方法:attachEvent() 和 detachEvent() .这两个方法接收相同的两个参数:事件处理程序名称和事件处理程序函数.通过 at ...

  9. 2020.11.18第十三章 事件(事件处理程序;事件对象;事件类型:UI事件;焦点事件;鼠标与键盘事件 变动事件 模拟事件)

    事件处理程序 html事件处理程序(直接在html中书写script) <!-- //#### 事件处理程序 //html时间程序 可以直接在HTML文件中写,而且还可以引用其他地方的方法和函数 ...

  10. JavaScript三种事件绑定的方式(DOM的0级、2级、3级事件处理程序)

    JS事件绑定的方式: ①.行内绑定 ②.动态绑定 ③.事件监听 一.行内绑定[DOM0级事件处理程序]: 例:<标签 属性列表 事件="事件的处理程序" /> 虽然可以 ...

最新文章

  1. python第三方库下载-python 第三方库下载
  2. 使用 Circular Reveal 动画让页面跳转更炫酷
  3. Android Material Design之在RecyclerView中嵌套CardView实现
  4. 第三次学JAVA再学不好就吃翔(part21)--局部变量与成员变量
  5. nginx配置文件中的location中文详解
  6. 构建一个简单的卷积神经网络,使用DRL框架tianshou匹配DQN算法
  7. zabbix邮件发送3.2.4
  8. 工程管理 -- makefile
  9. 《编写可维护的 JavaScript》读书笔记第7章:事件处理
  10. jQuery WeUI日历calendar时间段(开始日期默认选中日期是今天,结束日期设置最小日期),显示日期格式是yyyy年mm月dd日
  11. html中怎样设置放大功能,CSS如何设置图片放大效果?
  12. 技术人攻略访谈三十六-马鉴:玩Flash十五年,养出一只“神经猫”
  13. 关于Handling Unit SAP包装
  14. ubantu20.04 ros的安装
  15. JS-表格行的动态删除和添加(insertRow deleteRow)
  16. 猫加路由加服务器加交换机怎么配置文件,猫和路由器以及交换机的连接方法[图解]...
  17. SDWAN组网与传统组网方式的对比
  18. ECharts Title文字前添加图片
  19. echarts x 起始_echarts中如何在dataZoom 最左侧和最右侧始终显示起始和结束的值
  20. Rockchip 休眠唤醒 开发指南

热门文章

  1. icesat2:strong beam and weak beam
  2. conda安装包出现conda info (package)...的解决方法
  3. 服务器管理器添加php,为web服务器添加php的支持
  4. Android studio 4.0 Layout Inspector查看当前Activity
  5. Android 自定义View关于measure流程的基本思路整理
  6. android仿IOS,滑动隐藏底部ScrollView
  7. 哪一个瞬间,点燃了你的离职决心?
  8. 幅频响应 matlab画法,MATLAB环境下频率响应曲线的绘制方法.pdf
  9. 接口自动化测试框架搭建(6、对接口进行mock的方法封装)--python+HTMLTestRunnerCN+request+unittest+mock+db
  10. python找不到指定的路径_[Python学习]错误篇二:切换当前工作目录时出错——FileNotFoundError: [WinError 3] 系统找不到指定的路径...