多线程: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,如需转载请自行联系原作者


相关文章
|
4天前
|
开发框架 .NET C#
C#|.net core 基础 - 删除字符串最后一个字符的七大类N种实现方式
【10月更文挑战第9天】在 C#/.NET Core 中,有多种方法可以删除字符串的最后一个字符,包括使用 `Substring` 方法、`Remove` 方法、`ToCharArray` 与 `Array.Copy`、`StringBuilder`、正则表达式、循环遍历字符数组以及使用 LINQ 的 `SkipLast` 方法。
|
2月前
|
C# 开发者 Windows
在VB.NET项目中使用C#编写的代码
在VB.NET项目中使用C#编写的代码
45 0
|
1天前
|
存储 消息中间件 NoSQL
Redis 入门 - C#.NET Core客户端库六种选择
Redis 入门 - C#.NET Core客户端库六种选择
22 8
|
1天前
|
XML 存储 安全
C#开发的程序如何良好的防止反编译被破解?ConfuserEx .NET混淆工具使用介绍
C#开发的程序如何良好的防止反编译被破解?ConfuserEx .NET混淆工具使用介绍
7 0
|
5天前
|
SQL JSON BI
最好的 C# .NET 报告工具
最好的 C# .NET 报告工具
13 0
|
1月前
|
SQL 存储 关系型数据库
C#一分钟浅谈:使用 ADO.NET 进行数据库访问
【9月更文挑战第3天】在.NET开发中,与数据库交互至关重要。ADO.NET是Microsoft提供的用于访问关系型数据库的类库,包含连接数据库、执行SQL命令等功能。本文从基础入手,介绍如何使用ADO.NET进行数据库访问,并提供示例代码,同时讨论常见问题及其解决方案,如连接字符串错误、SQL注入风险和资源泄露等,帮助开发者更好地利用ADO.NET提升应用的安全性和稳定性。
89 6
|
1月前
|
算法 Java 中间件
C#/.NET/.NET Core优质学习资料,干货收藏!
C#/.NET/.NET Core优质学习资料,干货收藏!
|
1月前
|
人工智能 开发框架 算法
C#/.NET/.NET Core技术前沿周刊 | 第 2 期(2024年8.19-8.25)
C#/.NET/.NET Core技术前沿周刊 | 第 2 期(2024年8.19-8.25)
|
1月前
|
缓存 开发框架 算法
C#/.NET这些实用的编程技巧你都会了吗?
C#/.NET这些实用的编程技巧你都会了吗?
|
1月前
|
传感器 应用服务中间件 Linux
C#/.NET/.NET Core技术前沿周刊 | 第 3 期(2024年8.26-8.31)
C#/.NET/.NET Core技术前沿周刊 | 第 3 期(2024年8.26-8.31)