多线程:C#.NET中使用BackgroundWorker在模态对话框中显示进度条

简介:

我们使用C#.NET编写WinForm程序时,有时候为了实现在模态对话框中实时显示后台操作的进度,这个时候需要借助于多线程操作在子窗体中显示进度条状态,在父窗体中进行后台操作。你可以在Thread类中自己创建两个线程以完成这个操作,不过C#.NET提供了BackgroundWorker对象可以帮助我们非常方便地来实现这个过程。有关Backgroundworker对象的时候我在“C#遍历文件读取Word内容以及实用BackgroundWoker对象打造平滑进度条”一文中有过介绍,大家可以去看看。

  这里是一个示例,其中展示了如何使用Backgroundworker对象在模态对话框中显示后台操作的实时进度条。

  首先是主窗体代码:

复制代码
 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 
11  namespace  ModalProgressDialog
12  {
13       public   partial   class  Form1 : Form
14      {
15           protected  BackgroundWorker worker  =   new  BackgroundWorker();
16           protected  Form2 frm  =   new  Form2();
17 
18           public  Form1()
19          {
20              worker.DoWork  +=   new  DoWorkEventHandler(worker_DoWork);
21              worker.ProgressChanged  +=   new  ProgressChangedEventHandler(worker_ProgressChanged);
22              worker.RunWorkerCompleted  +=   new  RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
23 
24              InitializeComponent();
25          }
26 
27           private   void  button1_Click( object  sender, EventArgs e)
28          {
29              worker.WorkerReportsProgress  =   true ;            
30              worker.RunWorkerAsync();
31              frm.ShowDialog();
32          }
33 
34           void  worker_RunWorkerCompleted( object  sender, RunWorkerCompletedEventArgs e)
35          {
36              frm.Close();
37              MessageBox.Show( " Done " );
38          }
39 
40           void  worker_ProgressChanged( object  sender, ProgressChangedEventArgs e)
41          {
42              frm.ProgressValue  =  e.ProgressPercentage;
43          }
44 
45           void  worker_DoWork( object  sender, DoWorkEventArgs e)
46          {
47              CountTheTime();
48          }
49 
50           private   void  CountTheTime()
51          {
52               int  initialValue  =   100
53               for  ( int  count  =   0 ; count  <  initialValue; count  =  count  +   2
54              { 
55                  Thread.Sleep( 1000 );
56                  worker.ReportProgress(count); 
57              }
58          }
59      }
60  }
复制代码

 

  主窗体中只有一个按钮,当被点击时,会由BackgroundWorker对象以异步的方式去执行一个假象的后台操作CountTheTime方法。CountTheTime方法从0到100以步长为2每隔1秒更新一下进度条状态,因此这个假象的后台操作大约会持续50秒左右的时间。当程序执行时,进度条指示窗口以模态对话框的形式被弹出,然后实时显示后台操作的进度。

  BackgroundWorker对象有三个主要的事件:

  DoWork - 当BackgroundWorker对象的多线程操作被执行时触发。

  RunWokerCompleted - 当BackgroundWoker对象的多线程操作完成时触发。

  ProgressChanged - 当BackgroundWorker对象的多线程操作状态改变时触发。

  另外还有一个非常重要的属性WorkerReportsProgress - 如果想让BackgroundWorker对象以异步的方式报告线程实时进度,必须将该属性的值设为true。

  BackgroundWorker对象的ReportProgress方法用于向主线程返回后台线程执行的实时进度。

  下面是子窗体的代码:

复制代码
 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 
10  namespace  ModalProgressDialog
11  {
12       public   partial   class  Form2 : Form
13      {
14           public   int  ProgressValue 
15          {
16               get  {  return   this .progressBar1.Value; }
17               set  { progressBar1.Value  =  value; }
18          }
19 
20           public  Form2()
21          {
22              InitializeComponent();
23          }
24      }
25  }
复制代码

  子窗体中放置了一个ProgressBar控件,对外可以通过ProgressValue属性来获取和修改进度条的当前值。同时,我们可以将子窗体的FormBorderStyle属性设为FixedDialog以使其看起来更像对话框,然后将MaximizeBoxMinimizeBox都设为false,将ControlBox属性设为false以隐藏窗体关闭按钮。在父窗体中,我们通过BackgroundWorker对象的RunWorkerAsync方法触发DoWork事件,此时CountTheTime()方法被执行。在CountTheTime()方法中,通过ReportProgress()方法从后台进程(父窗体)传递进度指示到主UI线程(子窗体)中,这样同时会触发ProgressChanged事件,然后我们在该事件中更新子窗体的进度条状态。下面是程序执行时的截图。

   注意,使用BackgroundWorker时不能在工作线程中访问UI线程部分,即你不能在BackgroundWorker的事件和方法中操作UI,否则会抛跨线程操作无效的异常。常用的方法是在主窗体的构造函数中添加CheckForIllegalCrossThreadCalls = false;语句。或者使用Thread类创建一个单独的线程,然后使用Invoke方法。可以参考下面这些内容:

http://www.cnblogs.com/chorrysky/archive/2007/02/10/646891.html

http://blog.csdn.net/marklr/archive/2009/07/10/4338518.aspx

http://www.cnblogs.com/kingsky/archive/2009/02/18/1353322.html


本文转自Jaxu博客园博客,原文链接:http://www.cnblogs.com/jaxu/archive/2011/05/13/2045702.html,如需转载请自行联系原作者


相关文章
|
15天前
|
数据可视化 网络协议 C#
C#/.NET/.NET Core优秀项目和框架2024年3月简报
公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架(每周至少会推荐两个优秀的项目和框架当然节假日除外),公众号推文中有项目和框架的介绍、功能特点、使用方式以及部分功能截图等(打不开或者打开GitHub很慢的同学可以优先查看公众号推文,文末一定会附带项目和框架源码地址)。注意:排名不分先后,都是十分优秀的开源项目和框架,每周定期更新分享(欢迎关注公众号:追逐时光者,第一时间获取每周精选分享资讯🔔)。
|
1月前
|
SQL 数据库 C#
C# .NET面试系列十一:数据库SQL查询(附建表语句)
#### 第1题 用一条 SQL 语句 查询出每门课都大于80 分的学生姓名 建表语句: ```sql create table tableA ( name varchar(10), kecheng varchar(10), fenshu int(11) ) DEFAULT CHARSET = 'utf8'; ``` 插入数据 ```sql insert into tableA values ('张三', '语文', 81); insert into tableA values ('张三', '数学', 75); insert into tableA values ('李四',
65 2
C# .NET面试系列十一:数据库SQL查询(附建表语句)
|
1月前
|
开发框架 算法 搜索推荐
C# .NET面试系列九:常见的算法
#### 1. 求质数 ```c# // 判断一个数是否为质数的方法 public static bool IsPrime(int number) { if (number < 2) { return false; } for (int i = 2; i <= Math.Sqrt(number); i++) { if (number % i == 0) { return false; } } return true; } class Progr
58 1
|
1月前
|
并行计算 安全 Java
C# .NET面试系列四:多线程
<h2>多线程 #### 1. 根据线程安全的相关知识,分析以下代码,当调用 test 方法时 i > 10 时是否会引起死锁? 并简要说明理由。 ```c# public void test(int i) { lock(this) { if (i > 10) { i--; test(i); } } } ``` 在给定的代码中,不会发生死锁。死锁通常是由于两个或多个线程互相等待对方释放锁而无法继续执行的情况。在这个代码中,只有一个线程持有锁,且没有其他线程参与,因此不
105 3
|
3月前
|
Linux C# 开发工具
C#开源的一款友好的.NET SDK管理器
C#开源的一款友好的.NET SDK管理器
|
9天前
|
开发框架 前端开发 JavaScript
采用C#.Net +JavaScript 开发的云LIS系统源码 二级医院应用案例有演示
技术架构:Asp.NET CORE 3.1 MVC + SQLserver + Redis等 开发语言:C# 6.0、JavaScript 前端框架:JQuery、EasyUI、Bootstrap 后端框架:MVC、SQLSugar等 数 据 库:SQLserver 2012
|
1月前
|
开发框架 人工智能 .NET
C#/.NET/.NET Core拾遗补漏合集(持续更新)
C#/.NET/.NET Core拾遗补漏合集(持续更新)
|
1月前
|
SQL 存储 关系型数据库
C# .NET面试系列十:数据库概念知识
#### 1. 为什么要一定要设置主键? 设置主键是数据库设计中的一个重要概念,有几个主要原因: 1、唯一性 ```c# 主键必须保证表中的每一行都有唯一的标识。这样可以避免数据冗余和不一致性。如果没有主键或者主键不唯一,就可能出现数据混乱或错误。 ``` 2、查询性能 ```c# 数据库系统通常会使用主键来加速数据检索。主键通常会被索引,这样可以更快速地找到特定行的数据,提高查询效率。 ``` 3、关联性 ```c# 主键常常用于建立表与表之间的关系。在关系数据库中,一个表的主键通常与其他表中的外键建立关联,这种关系对于数据的一致性和完整性非常重要。 ``` 4、数据完
131 1
C# .NET面试系列十:数据库概念知识
|
1月前
|
XML 开发框架 .NET
C# .NET面试系列八:ADO.NET、XML、HTTP、AJAX、WebService
## 第二部分:ADO.NET、XML、HTTP、AJAX、WebService #### 1. .NET 和 C# 有什么区别? .NET(通用语言运行时): ```c# 定义:.NET 是一个软件开发框架,提供了一个通用的运行时环境,用于在不同的编程语言中执行代码。 作用:它为多语言支持提供了一个统一的平台,允许不同的语言共享类库和其他资源。.NET 包括 Common Language Runtime (CLR)、基础类库(BCL)和其他工具。 ``` C#(C Sharp): ```c# 定义: C# 是一种由微软设计的面向对象的编程语言,专门为.NET 平台开发而创建。 作
174 2
|
1月前
|
开发框架 中间件 .NET
C# .NET面试系列七:ASP.NET Core
## 第一部分:ASP.NET Core #### 1. 如何在 controller 中注入 service? 在.NET中,在ASP.NET Core应用程序中的Controller中注入服务通常使用<u>依赖注入(Dependency Injection)</u>来实现。以下是一些步骤,说明如何在Controller中注入服务: 1、创建服务 首先,确保你已经在应用程序中注册了服务。这通常在Startup.cs文件的ConfigureServices方法中完成。例如: ```c# services.AddScoped<IMyService, MyService>(); //
63 0