概述
Winform开发时,偶尔会在一个耗时的处理中用到Application.DoEvents()这个方法,可以让UI线程在当前代码上下文中切换去处理其它Windows消息,从而避免界面的假死。
例如,经常会这么用:
public static void Delay(int nMilliSeconds)
{
DateTime dt = DateTime.Now;
dt = dt.AddMilliseconds(nMilliSeconds);
while (dt > DateTime.Now)
{
Application.DoEvents();//转让控制权
}
return;
}
在UI线程中调用这个方法,就可以阻塞当前执行的上下文一段时间,阻止代码继续执行,但同时又不会导致界面假死。效果类似于Thread.Sleep(),但Sleep()是让UI线程直接阻塞,从而停止响应。
这种功能当然用多线程是可以做到的。但这种方式相比多线程的优势就在于代码简洁和无需做线程同步。
从应用的角度来讲,这个方法是一大利器,可以在单线程里实现类似多线程的效果。但是既然如此,为什么微软的官方文档里都没有看到这个推荐使用这个方法呢?猜想这个方法应该有较大的副作用。
随后在CSDN一篇帖子上看到一位大佬讲述了这个方法的历史,以下摘自原帖:
DoEvents 是 vb(4、5、6)的产物,因为那是单线程的。
它的机制是将你的应用中尚未触发的windows消息大乱次序、提前触发。比如说你在鼠标点击某个控件时会去调用过程a,在鼠标在此控件移动时会去调用过程b,同时在timer定时器到时时回去调用过程c,那么你会看到DoEvents 造成了在a尚未结束时反复调用了b、c等等过程,主线程中明明是顺序的代码,调用时一片混乱无法调试。而且往往会导致事件的爆炸性的循环调用(类似于无线递归没有节制),直至系统资源耗尽而崩溃。
正常的主线程异步操作,是可以明确地知道过程在主线程中被调用的先后次序的,可以明白地调试代码(明白地看懂调用堆栈)。主线程都是先调用完a,然后才可能调用b、c,并不是在过程中去拆自己的台。因此如果需要循环触发,那么就使用定时器。
DoEvents是vb那个时代的产物,应该终止与vb6(1998年)的时代。如果你要简单移植vb6的程序,可以用它。如果不是就不要用它。另外,在应用程序设计中搞“死循环”这是很令人不忍看、不忍“闻”的设计方式。如果你认为主线程经常要重复干一件(逻辑的)事儿,就必须写一个死循环,那么我只能说我们是绝对不用这样的程序员的。
在设计上,除非万不得已实在活不下去了,否则不允许随便写“死循环、阻塞”的代码。
写死循环,是因为有些人只知道刚入门学c等等几十行的简单小计算程序时学到的那种思路,因为那些是“输入-输出”式的简单函数。
如果你学习交互式程序设计,假设有10个独立的(貌似循环)的功能行为,那么凡是交互部分,都必须“断开”,然后每一个片段都必须是事件驱动(包括定时器事件驱动),这样才能组合成为一个完善的应用。难道你要写10个死循环,然后再胡乱地DoEvents调用?这是编程大忌。把设计中各种事件循环发生,代码上写成许多个死循环,这是没有学过应用程序设计的表现(可能只是从一些数学相关的课程中学了一些简单的函数编程)。一定要从设计思路上学会事件驱动的设计方法,而不是纠结于编程语句。
原贴地址:
Application.DoEvents();多次调用会有什么隐患,望有经验的朋友分享下!
这里所说的导致一些代码的逻辑顺序混乱,这种现象倒没有遇到过。导致效率变低倒是有。这种代码本身就违背了程序设计规范,是过程式编程的遗物,应当尽量避免使用。该用多线程还是得用多线程。
最后
以上就是舒服鸭子为你收集整理的【Winform】关于Application.DoEvents()的理解的全部内容,希望文章能够帮你解决【Winform】关于Application.DoEvents()的理解所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复