WinForm二三事(三)Control.Invoke&Control.BeginInvoke
从异常开始
在上一篇文章中,为了提高用户体验,使用delegate构造一个异步操作,但是在这个异步操作里操作UI控件的属性的时候却发生异常。实际上使用delegate构造异步操作这种方式,在背后还是创建了一个worker thread,从不是创建UI的thread里去操作UI元素的属性就会抛出这个异常。
不过,如果我们不在Visual Studio里运行这个程序,直接运行,这个异常却不会出现。通过查看异常的StackTrace,发现该异常是在获取Control的句柄时抛出的:
at System.Windows.Forms.Control.get_Handle()
at System.Windows.Forms.Control.set_WindowText(String value)
at System.Windows.Forms.Control.set_Text(String value)
at System.Windows.Forms.ButtonBase.set_Text(String value)//..省略...
祭出Reflector,看看相关代码:
1: public IntPtr Handle
2: {
3: get
4: {
5: if ((checkForIllegalCrossThreadCalls && !inCrossThreadSafeCall) && this.InvokeRequired)
6: {
7: throw new InvalidOperationException(SR.GetString("IllegalCrossThreadCall", new object[] { this.Name }));
8: }
9: if (!this.IsHandleCreated)
10: {
11: this.CreateHandle();
12: }
13: return this.HandleInternal;
14: }
15: }
然后是主要检查checkForIllegalCrossThreadCalls、inCrossThreadSafeCall两个字段以及InvokeRequired,InvokeRequired的职责是判断当前运行的线程是不是与窗体主线程是同一个线程。
通过字面理解checkForIllegalCrossThreadCalls的意思就是“跨线程调用时是不是检查”。而这个字段在Control的静态构造函数里被设置为:checkForIllegalCrossThreadCalls = Debugger.IsAttached(checkForIllegalCrossThreadCalls 还通过CheckForIllegalCrossThreadCalls属性公开了 ),现在明白了为啥在Visual Studio里调试程序报异常,而独立运行却不报了吧。
实际上如果在不是创建控件的线程里设置控件的属性抛出异常是正常的,不抛才不正常,我们不能为了异常而异常,如果多个线程访问控件属性,可能会有线程安全的问题,造成控件运行不稳定。那解决之道是什么?
只在创建控件的线程里设置控件的属性
废话,我当然知道这样是可以的,但是两个线程都在自顾自的运行,我有什么办法让别的线程停下手头的工作,来执行我分派的任务,这又不是两个人,我可以跟他说下。嘿,您还别说,这里的机制还真像两个人,甲线程发个短信给乙线程说,哥们,我有个事儿自己不好处理,怕出问题,你抽空儿给我处理下。根据甲线程发短信的方式,甲线程要么发了短信后就忙自己的事儿然后等乙线程处理完后的消息,要么一直在那里傻傻的等待着乙线程处理完。
Control.Invoke&Control.BeginInvoke
Control.Invoke和Control.BeginInvoke就是“发短信”的方法,如果使用Control.Invoke发短信,那么甲线程就会像个痴情的汉子,一直等待着乙线程的回音,而如果使用Control.BeginInvoke发送短信,那发完短信后,甲线程就会忙活自己的,等乙线程处理完再来瞧瞧。
注意:有人看到了BeginInvoke方法来了个Begin,心里可能在想,这是异步的特征啊,那是不是像上篇文章中使用delegate的BeginInvoke方法那样,启动一个worker thread?记住,这里的BeginInvoke是异步操作,但不是通过线程来实现的,具体方式后面有介绍。
我们先来看看如何使用Control.Invoke和Control.BeginInvoke(本文为了区分Control.BeginInvoke与delegate.BeginInvoke的区别,一直带上Control前缀)来发短信:
1: /// <summary>2: /// 假设这是一个查询数据的方法,会很耗时3: /// </summary>4: /// <returns>返回从数据库查询结果</returns>5: private补充:Web开发 , ASP.Net ,
- 更多asp疑问解答:
- asp正则过滤重复字符串的代码
- 用asp过滤全部html但保留br类似的符号
- 会asp,但感觉asp要过点,想学php。但我一般做的都是小公司的站,用access数
- PHP的空间可以用ASP的源代码吗?
- 以前做asp程序,现在应该怎样发展?是学.net还是php
- 以前做asp程序,现在应该怎样发展?是学.net还是php
- 想做一个市级的人才网acess,sql数据库,语言asp,jsp,php分别用哪种好
- jsp,asp,php 区别
- 我想找一个有比较多漏洞的网站的源码,比如可以asp,php注入等都可以。供学习研究用。请提供下载地址。。
- 现在候找人做个网站,用ASP,还是PHP语言去做好
- asp,php ,jsp,.net 对于做网站前台的重要吗?
- asp和php的区别是什么?
- 我是新手SEO菜鸟 请问wp dw php asp cms myspl dede 这些软件应该如何区分呀?
- 网页制作相关的三种语言:ASP JSP PHP那个好点,简单点?
- 网页制作相关的三种语言:ASP JSP PHP那个好点,简单点?