为了让程序尽快响应用户操作,在开发Windows应用程序时经常会使用到线程。对于耗时的操作如果不使用线程将会是UI界面长时间处于停滞状态,这种情况是用户非常不愿意看到的,在这种情况下我们希望使用线程来解决这个问题。
下面是一个使用多线程操作界面UI的代码:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Text;
  7. using System.Windows.Forms;
  8. using System.Threading;
  9. namespace ThreadPoolDemo
  10. {
  11. public partial class ThreadForm : Form
  12. {
  13. public ThreadForm()
  14. {
  15. InitializeComponent();
  16. }
  17. private void btnThread_Click(object sender, EventArgs e)
  18. {
  19. Thread thread = new Thread(new ThreadStart(Run));
  20. thread.Start();
  21. }
  22. private void Run()
  23. {
  24. while (progressBar.Value < progressBar.Maximum)
  25. {
  26. progressBar.PerformStep();
  27. }
  28. }
  29. }
  30. }

我们的本意是点击“启动”按钮来启动模拟一个操作,在进度条中显示操作的总体进度。不过如果我们真的点击“启动”按钮会很失望,因为它会抛出一个System.InvalidOperationException异常,异常描述就是“线程间操作无效: 从不是创建控件‘progressBar’的线程访问它。”
CheckForIllegalCrossThreadCalls属性
之所以会出现这样的情况是因为在.NET中做了限制,不允许在调试环境下使用线程访问并非它自己创建的UI控件,这么做可能是怕在多线程环境下对界面控件进行操作会出现不可预知的情况,如果开发者可以确认自己的代码操作界面不会出现问题,可以用比较简单的方法解决,那就是设置CheckForIllegalCrossThreadCalls这个静态属性,它默认是true,如果将其设为false的话,以后在多线程环境下操作界面也不会抛出异常了,我们上面的代码可以修改为:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Windows.Forms;
  9. using System.Threading;
  10. namespace ThreadPoolDemo
  11. {
  12. public partial class ThreadForm : Form
  13. {
  14. public ThreadForm()
  15. {
  16. InitializeComponent();
  17. }
  18. private void btnThread_Click(object sender, EventArgs e)
  19. {
  20. //指示是否对错误线程的调用,即是否允许在创建UI的线程之外访问线程
  21. CheckForIllegalCrossThreadCalls = false;
  22. Thread thread = new Thread(new ThreadStart(Run));
  23. thread.Start();
  24. }
  25. private void Run()
  26. {
  27. while (progressBar.Value < progressBar.Maximum)
  28. {
  29. progressBar.PerformStep();
  30. }
  31. }
  32. }
  33. }

这样再执行程序就不会抛出异常了。

不过使用上面的代码我们可能还有些犯嘀咕,毕竟是不允许直接在线程中直接操作界面的,那么我们还可以用Invoke方法。

Invoke方法来操作界面
下面是一个例子:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Windows.Forms;
  9. using System.Threading;
  10. namespace ThreadPoolDemo
  11. {
  12. public partial class ThreadForm : Form
  13. {
  14. //定义delegate以便Invoke时使用
  15. private delegate void SetProgressBarValue(int value);
  16. public ThreadForm()
  17. {
  18. InitializeComponent();
  19. }
  20. private void btnThread_Click(object sender, EventArgs e)
  21. {
  22. progressBar.Value = 0;
  23. //指示是否对错误线程的调用,即是否允许在创建UI的线程之外访问线程
  24. //CheckForIllegalCrossThreadCalls = false;
  25. Thread thread = new Thread(new ThreadStart(Run));
  26. thread.Start();
  27. }
  28. //使用线程来直接设置进度条
  29. private void Run()
  30. {
  31. while (progressBar.Value < progressBar.Maximum)
  32. {
  33. progressBar.PerformStep();
  34. }
  35. }
  36. private void btnInvoke_Click(object sender, EventArgs e)
  37. {
  38. progressBar.Value = 0;
  39. Thread thread = new Thread(new ThreadStart(RunWithInvoke));
  40. thread.Start();
  41. }
  42. //使用Invoke方法来设置进度条
  43. private void RunWithInvoke()
  44. {
  45. int value = progressBar.Value;
  46. while (value< progressBar.Maximum)
  47. {
  48. //如果是跨线程调用
  49. if (InvokeRequired)
  50. {
  51. this.Invoke(new SetProgressBarValue(SetProgressValue), value++);
  52. }
  53. else
  54. {
  55. progressBar.Value = ++value;
  56. }
  57. }
  58. }
  59. //跟SetProgressBarValue委托相匹配的方法
  60. private void SetProgressValue(int value)
  61. {
  62. progressBar.Value = value;
  63. }
  64. }
  65. }

这个方法的功能跟上面的操作是一样的,只不过不需要设置CheckForIllegalCrossThreadCalls属性,而且还不会抛出异常。

多线程与UI操作(二)的更多相关文章

  1. C# Wpf异步修改UI,多线程修改UI(二)

    1.使用定时器异步修改 这是相对比较简单的方法 在Wpf中定时器使用DiapatcherTimer,不使用Timer原因: 在一个应用程序中,Timer会重复生成time事件,而DispatcherT ...

  2. 多线程与UI操作(一)

    C#中禁止跨线程直接访问控件,InvokeRequired是为了解决这个问题而产生的,当一个控件的InvokeRequired属性值为真时,说明有一个创建它以外的线程想访问它. 此时它将会在内部调用n ...

  3. Android 子线程 UI 操作真的不可以?

    作者:vivo 互联网大前端团队- Zhang Xichen 一.背景及问题 某 SDK 有 PopupWindow 弹窗及动效,由于业务场景要求,对于 App 而言,SDK 的弹窗弹出时机具有随机性 ...

  4. 在多线程中进行UI操作

    那么在子线程中的UI操作如何处理呢?有两种方法: 一:在子线程,你需要进行的UI操作前添加dispatch_async函数,即可将代码块中的工作转回到主线程 dispatch_async(dispat ...

  5. 在多线程中进行UI操作--ios学习笔记

    iOS 上不建议在非主线程进行UI操作,在非主线程进行UI操作有很大几率会导致程序崩溃,或者出现预期之外的效果. 我开始不知道这一点,在子线程中进行了弹窗操作,结果程序就出问题了! 报的错误是(EXC ...

  6. Java多线程编程——进阶篇二

    一.线程的交互 a.线程交互的基础知识 线程交互知识点需要从java.lang.Object的类的三个方法来学习:    void notify()           唤醒在此对象监视器上等待的单个 ...

  7. 拒绝卡顿——在WPF中使用多线程更新UI

    原文:拒绝卡顿--在WPF中使用多线程更新UI 有经验的程序员们都知道:不能在UI线程上进行耗时操作,那样会造成界面卡顿,如下就是一个简单的示例: public partial class MainW ...

  8. Qt中如何禁掉所有UI操作以及注意事项(处理各个widget的eventFilter这一层,但是感觉不好,为什么不使用QApplication呢)

    刚做完的一个项目,在测试时出现了一个问题:由于多线程的存在,当进行语音识别时:如果用户点击程序界面上的button或者其他接受点击事件后会发出信号的widget时,程序会crash ! 后来尝试着从多 ...

  9. java 轻量级同步volatile关键字简介与可见性有序性与synchronized区别 多线程中篇(十二)

    概念 JMM规范解决了线程安全的问题,主要三个方面:原子性.可见性.有序性,借助于synchronized关键字体现,可以有效地保障线程安全(前提是你正确运用) 之前说过,这三个特性并不一定需要全部同 ...

随机推荐

  1. 远程发送文件失败(scp)

    出现这种情况的原因是之前保存过192.168.210.134的密钥. 碰到这种情况进行如下操作: ①查看隐藏文件 [root@localhost ~]# ls -a    .ssh ②切换到 .ssh ...

  2. IDEA "Library source does not match the bytecode for class"问题

    问题描述 Jar包更新后,报错信息:"Library source does not match the bytecode for class" 经检查,发现Jar内容还是旧版本的 ...

  3. MySQL数据库5.7全文索引的坑

    1.引擎必须是MyIsAm 2.创建全文索引:ALTER TABLE articles ADD FULLTEXT (title,body); 3.注意全文搜索的字段必须等于或者大于4个字节才会有效 4 ...

  4. redis外网无法连接问题

    1.外网无法连接redis 解决方法: 把redis.conf里的bind 127.0.0.1注释掉,不行的话把127.0.0.1修改成0.0.0.0 2.make的时候显示没有gcc 解决方法: 安 ...

  5. 【ABAP系列】【第五篇】SAP ABAP7.50 之用户接口

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列][第五篇]SAP ABAP7.5 ...

  6. MySQLdb._exceptions.OperationalError: (2059, <NULL>)

    这是将 将数据迁移至mysql8.0时遇到的问题, 在网上找到了解决方案(亲测有用), 这是因为mysql8.0密码加密的问题,mysql8.0对用户密码的加密方式为caching_sha2_pass ...

  7. Asp.NetCore应用--部署到 ubuntu 进行托管

    准备过程 netcore linux发布包(本人是通过vs2017发布) ubuntu 16.0.4虚机 进行托管 ubuntu  netcore发布文件路径 服务器设置为将对 http://< ...

  8. Java 200道题

    1. junit用法,before,beforeClass,after, afterClass的执行顺序 一个测试类单元测试的执行顺序为: @BeforeClass –> @Before –&g ...

  9. 自然语言处理工具pyhanlp分词与词性标注

    Pyhanlp分词与词性标注的相关内容记得此前是有分享过的.可能时间太久记不太清楚了.以下文章是分享自“baiziyu”所写(小部分内容有修改),供大家学习参考之用. 简介 pyhanlp是HanLP ...

  10. 如何决定使用 HashMap 还是 TreeMap? (转)

    问:如何决定使用 HashMap 还是 TreeMap? 介绍 TreeMap<K,V>的Key值是要求实现java.lang.Comparable,所以迭代的时候TreeMap默认是按照 ...