为了让程序尽快响应用户操作,在开发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. Window Position

    IE, Safari, Opera, and Chrome all provide screenLeft and screenTop properties that indicate the wind ...

  2. Python Deque 模块使用详解,python中yield的用法详解

    Deque模块是Python标准库collections中的一项. 它提供了两端都可以操作的序列, 这意味着, 你可以在序列前后都执行添加或删除. https://blog.csdn.net/qq_3 ...

  3. Number 和 Math 类

    Java Number & Math 类 一般地,当需要使用数字的时候,我们通常使用内置数据类型,如:byte.int.long.double 等. 然而,在实际开发过程中,我们经常会遇到需要 ...

  4. Tensorflow 保存和载入训练过程

    本节涉及点: 保存训练过程 载入保存的训练过程并继续训练 通过命令行参数控制是否强制重新开始训练 训练过程中的手动保存 保存训练过程前,程序征得同意 一.保存训练过程 以下方代码为例: import ...

  5. Django-ORM之ManyToManyField的使用-多对多关系

    表结构设计 多对多关系表创建外键,典型例子:书--作者--出版社,书与作者的关系就可以看作是多对多关系. # 表结构设计 class Book(models.Model): title = model ...

  6. mysql --single-transaction 在从库导入完数据以后要在配置文件/etc/my.cnf 中加上read_only=1的参数

    1.在做数据库的主从时,防止在这个过程中,有数据访问进来,要: 要想连super权限用户的写操作也禁止,就使用"flush tables with read lock;",这样设置 ...

  7. javaScript学习总结(二)——jQuery插件的开发

    概要 jQuery插件就是以jQuery库为基础衍生出来的库,jQuery插件的好处是封装功能,提高了代码的复用性,加快了开发速度,现在网络上开源的jQuery插件非常多,随着版本的不停迭代越来越稳定 ...

  8. python_0基础开始_day13

    第十三节 一,匿名函数 匿名函数 == 一行函数 lambda == def == 关键字 函数体中存放的是代码 生成器体中存放的也是代码 就是yield导致函数和生成器的结果不统一 lambda x ...

  9. spark教程(二)-shell操作

    spark 支持 shell 操作 shell 主要用于调试,所以简单介绍用法即可 支持多种语言的 shell 包括 scala shell.python shell.R shell.SQL shel ...

  10. Springboot实现上传文件接口,使用python的requests进行组装报文上传文件的方法

    记录瞬间 近段时间使用Springboot实现了文件的上传服务,但是在使用python的requests进行post上传时,总是报错. 比如: 1.Current request is not a m ...