在运动控制中错误应用Application.DoEvents()造成的问题


Application.DoEvents()以让UI线程在当前代码上下文中切换去处理其它Windows消息,从而避免界面的假死。

如在一个按钮单击事件中,需要每一秒改变label的Text属性,如下代码:

 private void button1_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < 50; i++)
            {
                Thread.Sleep(500);
                this.label1.Text = i.ToString();
            }
        }

编译运行,单击按钮,你并不会见到lable一直改变,等到执行完,你只会看见49。而加上 Application.DoEvents() 方法则可以看到一直更改的文本

 private void button1_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < 50; i++)
            {
                Thread.Sleep(500);
                this.label1.Text = i.ToString();
                Application.DoEvents();
            }
        }


勇哥在下面的WaitMotorDone函数中,原本使用的DoEvnets(),

本意是当用于ui调用时,可以在运动中能不卡住界面(有机会更新界面信息)。


image.png

你从函数名可以知道,此函数由运动函数调用,它等待轴停止,然后退出。

我的一个ptp运动函数调用了WaitMotorDone。


界面上一个按钮调用了这个ptp运动函数,当逻辑中有多条连续的ptp运动函数时,执行就异常了。

表现为第二个或者第三个ptp运动函数无效退了,即运动函数执行了轴没动作,但是函数执行完成了。


如果把WaitMotorDone中的Applictation.DoEvnets()注释了,问题就解决了。

当然,如果你用一个线程去调用运动函数,即使没有注释掉DoEvents(),也是没有问题的。


这说明Application.DoEvents()和ui线程有某些冲突。

毕竟只有winform才有消息循环,而Applictation.DoEvnets()就是处理消息循环的功能。


那么使用下面的代码,可以解决问题吗。

if (Application.MessageLoop)  Application.DoEvents();

这个代码的意思,勇哥参考微软的说明,指的是: 如果当前线程存在消息循环的值,则执行Applictation.DoEvnets()。

即如果是ui线程调用下这个if会命中,如果在其它线程下调用这个if会命中不了。

因此,加这个if也解决不了上面说的异常。



由网上找到的资料,表明Applictation.DoEvnets()实际上是VB时代的旧物,除了兼容考虑,其它情况下不要使用。

原文摘抄如下:


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调用?这是编程大忌。

把设计中各种事件循环发生,代码上写成许多个死循环,这是没有学过应用程序设计的表现
(可能只是从一些数学相关的课程中学了一些简单的函数编程)。
一定要从设计思路上学会事件驱动的设计方法,而不是纠结于编程语句。


所以, 各位同学们还是快快检查下自己的代码,放弃Applictation.DoEvnets()吧!


--------------------- 

作者:hackpig

来源:www.skcircle.com

版权声明:本文为博主原创文章,转载请附上博文链接!


本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

会员中心
搜索
«    2024年5月    »
12345
6789101112
13141516171819
20212223242526
2728293031
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 RSS 2.0 新闻聚合
  • 扫描加本站机器视觉QQ群,验证答案为:halcon勇哥的机器视觉
  • 点击查阅微信群二维码
  • 扫描加勇哥的非标自动化群,验证答案:C#/C++/VB勇哥的非标自动化群
  • 扫描加站长微信:站长微信:abc496103864
  • 扫描加站长QQ:
  • 扫描赞赏本站:
  • 留言板:

Powered By Z-BlogPHP 1.7.2

Copyright Your skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864