我們使用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以使其看起來更像對話方塊,然後將MaximizeBox和MinimizeBox都設為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