背景介绍

  在做程序的过程中,我们很可能遇到这样的情况:当我们执行一个比较耗时的操作,即界面加载数据量略大的时,在该操作未完成之前再去操作界面,就会出现停止响应的情况,这称为界面假死状态,那一个小圆圈转呀转的,想必大家看着就头疼。当然这是一个非常影响用户体验度的地方。

  怎么做出一个能够及时响应的用户界面呢?—多线程操作。

  引入BackgroundWorker组件:BackgroundWorker是·net里用来执行多线程任务的控件,它允许编程者在一个单独的线程上执行一些操作。

BackgroundWorker组件

  常用方法

  1.RunWorkerAsync 开始执行后台操作。引发 DoWork 事件

  2.CancelAsync 请求取消挂起的后台操作。

  注意:这个方法是将 CancellationPending 属性设置为 true,并不会终止后台操作。在后台操作中要检查

CancellationPending 属性,来决定是否要继续执行耗时的操作。

  3.ReportProgress引发 ProgressChanged 事件。

  常用属性

  1.CancellationPending 指示应用程序是否已请求取消后台操作。只读属性,默认为 false,当执行了 CancelAsync 方法后,值为 true。

  2.WorkerSupportsCancellation指示是否支持异步取消。要执行 CancelAsync 方法,需要先设置该属性为 true。

  3.WorkerReportsProgress指示是否能报告进度。要执行 ReportProgress 方法,需要先设置该属性为 true。

  常用事件

  1.DoWork 调用 RunWorkerAsync 方法时发生。

  2.RunWorkerCompleted后台操作已完成、被取消或引发异常时发生。

  3.ProgressChanged调用 ReportProgress 方法时发生。

  注意:在 DoWork 事件处理程序中不操作任何用户界面对象。而应该通过 ProgressChanged 和RunWorkerCompleted 事件与用户界面进行通信。

  如果想在 DoWork 事件处理程序中和用户界面的控件通信,可在用 ReportProgress 方法。ReportProgress(int percentProgress, object userState),可以传递一个对象。ProgressChanged 事件可以从参数ProgressChangedEventArgs 类的UserState 属性得到这个信息对象。这个事件也可以实现进度条功能,把任务的进度实时呈现给用户。

  简单的程序用BackgroundWorker 比 Thread 方便,Thread中和用户界面上的控件通信比较麻烦,需要用委托来调用控件的 Invoke 或BeginInvoke 方法,没有 BackgroundWorker 方便。

BackgroundWorker Demo

[csharp] view plain copy

  1. namespace BackgroundWorkerTest
  2. {
  3. public partial class Form1 : Form
  4. {
  5. public Form1()
  6. {
  7. InitializeComponent();
  8. backgroundWorker1.WorkerReportsProgress = true;//报告完成进度
  9. backgroundWorker1.WorkerSupportsCancellation = true;//允许用户终止后台线程
  10. }
  11. //开始按钮
  12. private void button1_Click(object sender, EventArgs e)
  13. {
  14. if (!backgroundWorker1.IsBusy )//判断backgroundWorker1是否正在运行异步操作
  15. {
  16. //backgroundWorker1.RunWorkerAsync();
  17. backgroundWorker1.RunWorkerAsync(1000);//开始执行后台操作,调用DoWork事件
  18. }
  19. }
  20. //DoWork事件声明要执行的耗时操作
  21. private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
  22. {
  23. e.Result = ListNumber(backgroundWorker1, e);//运算结果保存在e.Result中
  24. }
  25. bool ListNumber(object sender, DoWorkEventArgs e)
  26. {
  27. int num=(int)e.Argument;//接收传入的参数
  28. for (int i = 1; i <= num; i++)
  29. {
  30. if (backgroundWorker1.CancellationPending)//判断是否请求了取消后台操作
  31. {
  32. e.Cancel=true;
  33. return false;
  34. }
  35. //backgroundWorker1.ReportProgress(i * 100 / num);
  36. backgroundWorker1.ReportProgress(i * 100 / num,i);//报告完成进度
  37. Thread.Sleep(0);//后台线程交出时间片
  38. }
  39. return true;
  40. }
  41. private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
  42. {
  43. //将完成进度数据传给进度条
  44. progressBar1.Value = e.ProgressPercentage;
  45. label1.Text = e.ProgressPercentage + "%";
  46. //将中间计算结果在ListBox控件中显示出来
  47. listBox1.Items.Add(e.UserState);
  48. }
  49. Private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
  50. {
  51. if (!e.Cancelled && e.Error==null)
  52. {
  53. MessageBox.Show("处理完成了吗?  " + e.Result);
  54. }
  55. else//如果取消后台线程或发生了异常
  56. {
  57. MessageBox.Show("处理完成了吗?  false");
  58. }
  59. }
  60. //取消按钮
  61. private void button2_Click(object sender, EventArgs e)
  62. {
  63. if (backgroundWorker1.WorkerSupportsCancellation==true)
  64. {
  65. backgroundWorker1.CancelAsync();//取消后台操作
  66. backgroundWorker1.Dispose();//释放资源
  67. }
  68. }
  69. }
  70. }

总结:

  使用backgroundWorker实现多线程大致的步骤是:

  1、绑定线程,设置属性

  2、调用BackgroundWorker的RunWorkerAsync方法(可以传递参数),它将调用DoWork事件

  3、声明DoWork事件的委托方法,在后台执行耗时的操作

  4、在耗时操作中判断CancellationPending属性,如果为false则退出

  5、如果要向用户界面发送信息,则调用BackgroundWorker的ReportProgress方法,它将调用ProgressChanged事件(可以将改变通过object类型传递)

  6、在ProgressChanged事件的响应代码中将改变呈现给用户,类似进度条。

  7、如果需要取消耗时操作,则调用BackgroundWorker的CancelAsync方法,需要和步骤3一起使用

  总的来说就是用backgroundWorker组件来新建一个线程,把耗时的部分放到这个线程中在后台进行处理。这样就不会影响界面的正常使用。举个通俗的例子,在我们打开一个网页的时候,先加载完的总是文字,然后图片在慢慢出现。这就是线程的应用,网页打开的时候先呈现出文字,供用户浏览,然后把加载图片放到一个单独的线程中,异步的在后台执行,执行完毕后把图片呈现出来。

  这样就避免了一打开界面就加载大量信息,而造成的界面假死状态,大大提高了用户体验度。

BackgroundWorker 实现多线程操作相关推荐

  1. C#多线程操作界面控件的解决方案

    C#中利用委托实现多线程跨线程操作 - 张小鱼 2010-10-22 08:38 在使用VS2005的时候,如果你从非创建这个控件的线程中访问这个控件或者操作这个控件的话就会抛出这个异常.这是微软为了 ...

  2. .net开发中用BackgroundWorker实现多线程

    http://www.111cn.net/net/net/74654.htm BackgroundWorker是?net里用来执行多线程任务的控件,它允许编程者在一个单独的线程上执行一些操作.现在我们 ...

  3. FMDatabaseQueue 数据库多线程操作、事务处理

    SQLite数据库多线程操作: 在上面一节中已经讲过FMDB的用法了,接下来讲讲sqlite在都线程中的用法.如果应用中使用了多线程操作数据库,那么就需要使用FMDatabaseQueue来保证线程安 ...

  4. 一行 Python 实现并行化 -- 日常多线程操作的新思路 - 左手键盘,右手书 - SegmentFault...

    一行 Python 实现并行化 -- 日常多线程操作的新思路 - 左手键盘,右手书 - SegmentFault

  5. Shell多线程操作及线程数控制实例

    来源:http://www.jb51.net/article/51720.htm 这篇文章主要介绍了Shell多线程操作及线程数控制实例,文中从单线程实现一个需求开始,不断加入代码实现多线程以及线程数 ...

  6. python多线程读取数据库数据_python多线程操作MySQL数据库pymysql

    python多线程操作MySQL数据库pymysql 项目中使用多线程操作数据库提示错误:pymysql.err.InterfaceError: (0, "),原因是pymysql的exec ...

  7. MFC不能多线程操作控件的原因

    对于大多数mfc对象,请不要在线程间传递它们,不管是栈上的还是堆上的!原因如下:   mfc的大多数类不是线程安全的,调用传入对象的成员函数可能不会报错,但是未必能达到程序预定的功能!   mfc与界 ...

  8. python多线程读取数据库数据_Python基于多线程操作数据库相关知识点详解

    Python基于多线程操作数据库相关问题分析 本文实例分析了Python多线程操作数据库相关问题.分享给大家供大家参考,具体如下: python多线程并发操作数据库,会存在链接数据库超时.数据库连接丢 ...

  9. Core Data 多线程操作实战篇

    最近在解决百度音乐iPhone客户端偶现数据库操作crash的问题,顺手整理了下CoreData的多线程原则,以及实际开发时应该如何遵守这些原则. Core Data多线程操作的基本原则 不允许跨线程 ...

最新文章

  1. David与Vincent的博弈游戏[树型DP]
  2. Android关机流程源码分析
  3. Java实现URL下载图片到本地
  4. scala maven plugin
  5. ASP.NET 页面生存周期概览
  6. python数学公式pdf文件的转换_python转换文件 多种文件转换为pdf
  7. java 根据类名示例化类_Java LocalDateTime类| 带示例的getNano()方法
  8. nginx 带宽_谈谈Nginx和LVS各自的优缺点以及使用
  9. 爱奇艺数据中台建设组合拳:日志投递、统一数仓、大数据平台
  10. linux-stat查属
  11. CSS3 圆角 border-radius属性
  12. 是谁掌控了丁真的故事走向?
  13. Linux学习总结(51)——25个Linux服务器安全小贴士
  14. Java 设计模式之普通代理
  15. linux7 多路径配置,redhat7.3多路径配置
  16. Linux 防火墙 开放 端口 iptables
  17. 字符,字符集,字符编码
  18. linux 卸载java jdk1.6_Linux 下安装与卸载JDK(jdk-6u16-)
  19. c语言求圆柱的底面积和体积,计算圆柱的底面积和体积
  20. matlab张正友程序,张正友标定程序—MATLAB

热门文章

  1. 收费邮箱有哪些?收费邮箱有哪些真正的价值?
  2. 微雪电子SIM7000C NB-IOT Emqx MQTT 通信的详细测试过程
  3. 高校智慧实验室管理系统的实践应用
  4. 任正非回应美国封杀:不要煽动民族情绪,不能狭隘认为爱华为就用华为手机...
  5. EM算法-Jensen不等式
  6. 中国光纤通信技术现状和未来,如何发展好这个行业?
  7. 最新液氨市场的价格 液氨价格受那些因素影响
  8. RK3399平台开发系列讲解(PCI/PCI-E)5.53、PCIE RC侧 地址映射
  9. Java swt连接数据库实现员工绩效管理系统(可视化UI界面)
  10. android设备显示电脑内容,安卓手机怎样用电脑查看记事本内容