事件处理程序的处理顺序问题
2010-03-13 11:15
375 查看
这也是今天讨论到的一个话题,其实还是比较简单的。因为事件处理程序都是在主线程被执行的,所以主线程肯定是依次执行他们。那么究竟是什么决定了这个顺序呢?
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
其实要深入看的话,这是因为事件的处理程序是通过一个列表来管理的,就是EventHandlerList
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
为什么使用EventHandlerList? 这个问题之前就谈论过,默认情况下,客户端程序每为事件绑定一个处理程序,就需要在类型中产生一个delegate的引用,如此一来,如果事件很多的话,不利于较好地控制内存。但如果用EventHandlerList的话,则有利于统一管理所有的delegate
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); } } } }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
其实要深入看的话,这是因为事件的处理程序是通过一个列表来管理的,就是EventHandlerList
[HostProtection(SecurityAction.LinkDemand, SharedState=true)] public sealed class EventHandlerList : IDisposable { // Fields private ListEntry head; private Component parent; // Methods public 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 = Delegate.Combine(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); } } // Properties public 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 Types private sealed class ListEntry { // Fields internal Delegate handler; internal object key; internal EventHandlerList.ListEntry next; // Methods public 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; protected EventHandlerList listEventDelegates = new EventHandlerList(); private object NameChangedEventKey = new object(); public event EventHandler NameChanged { add { listEventDelegates.AddHandler(NameChangedEventKey, value); } remove { listEventDelegates.RemoveHandler(NameChangedEventKey, value); } } private string name; public string Name { get { return name; } set { name = value; if (listEventDelegates[NameChangedEventKey] != null) { listEventDelegates[NameChangedEventKey].DynamicInvoke(new object[] { this, null }); } } } } }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
为什么使用EventHandlerList? 这个问题之前就谈论过,默认情况下,客户端程序每为事件绑定一个处理程序,就需要在类型中产生一个delegate的引用,如此一来,如果事件很多的话,不利于较好地控制内存。但如果用EventHandlerList的话,则有利于统一管理所有的delegate
相关文章推荐
- 事件处理程序的处理顺序问题
- Sharepoint列表事件处理程序有小问题。
- Netty长连接的事件处理顺序问题
- 用事件队列解决GUI的操作顺序问题(Qt中处理方法)
- 使用欢迎使用事件处理程序向导的问题
- JavaScript将DOM事件处理程序封装为event.js 出现的低级错误问题
- 跨浏览器解决事件处理程序兼容问题
- 原生js解决对象事件处理程序添加和删除的兼容性问题
- Netty长连接的事件处理顺序问题
- JavaScript权威指南_168_第17章_事件处理_17.3-调用事件处理程序-返回值、调用顺序
- Netty长连接的事件处理顺序问题
- this指向问题——严格、非严格模式,事件处理程序
- Android中事件分发处理MotionEvent事件在onInterceptTouchEvent()、onTouchEvent()中的传递顺序【转】
- MFC程序的消息处理顺序
- javascript事件处理程序
- MFC程序中消息以及函数的处理顺序简介
- WSS3SDK之:如何创建一个事件处理程序Feature
- 鼠标滚动一次window.onscroll事件的函数在firfox与Ie中执行的次数不同问题的处理s
- Java 组件及事件处理实训 实训2:编写一个窗体程序,用于计算一元二次方程
- 使用HTML页面和一般处理程序模拟ASP.NET WebForms中的事件