在.NET WinForm程式中,大多數情況下我們是知道程式運作所需要的時間或步驟的,比如批量複制檔案時檔案的數量,資料導出或導入時資料的總行數等等。對于步驟比較确定的操作,如果程式執行過程時間較長,很容易使用BackgroundWorker結合ProgressBar來顯示一個實時的進度。相關内容大家可以看我部落格中的其它文章,有關如何使用BackgroundWorker和ProgressBar。但是,有的時候我們是不确定程式執行的具體步驟或時長的,比如連接配接一個遠端服務或資料庫服務,或者調用一個遠端過程或WebService等,這個時候我們就沒有辦法去觸發BackgroundWorker的ProgressChanged事件,是以也就不能實時去更新ProgressBar的進度了。有兩種替代的辦法可以解決這個問題。
第一是将ProgressBar的Style設定為Marquee而不是預設的Blocks。在Marquee模式下,進度條會不停地向前走用來模拟一個長時間的操作。事實上,Windows中也有很多類似的進度條,大多都是出現在對操作過程所需的步驟和時長不太确定的時候。這種方法很簡單,不過你仍然要将背景的執行過程放到多線程來執行,否則進度條會卡在UI線程中。一個好的辦法就是依舊使用BackgroundWorker組建,将背景的執行程式放到BackgroundWorker的DoWorker事件中,然後調用BackgroundWorker的RunWorkerAsync方法來異步執行程式。這樣,UI線程和背景執行程式的線程可以分開,進度條便不會再卡了。
第二種方法是使用System.Windows.Forms.Timer定時器控件,設定好Timer的Interval間隔時間,在Timer的Tick事件中來更新ProgressBar的進度。由于Timer天生就是多線程的,是以這種辦法實作起來很友善。
<a></a>
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 WindowsFormsApplication2
12 {
13 public partial class Form1 : Form
14 {
15 private BackgroundWorker worker = new BackgroundWorker();
16 private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
17 public Form1()
18 {
19 InitializeComponent();
20 this.progressBar1.Value = 0;
21 this.progressBar1.Maximum = 200;
22 this.progressBar1.Step = 1;
23 timer.Interval = 100;
24 timer.Tick += new EventHandler(timer_Tick);
25 worker.WorkerReportsProgress = true;
26 worker.DoWork += new DoWorkEventHandler(worker_DoWork);
27 worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
28 worker.RunWorkerAsync();
29 timer.Start();
30 }
31
32 void timer_Tick(object sender, EventArgs e)
33 {
34 if (this.progressBar1.Value < this.progressBar1.Maximum)
35 {
36 this.progressBar1.PerformStep();
37 }
38 }
39
40 void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
41 {
42 timer.Stop();
43 this.progressBar1.Value = this.progressBar1.Maximum;
44 MessageBox.Show("Complete!");
45 }
46
47 void worker_DoWork(object sender, DoWorkEventArgs e)
48 {
49 int count = 100;
50 for (int i = 0; i < count; i++)
51 {
52 Thread.Sleep(100);
53 }
54 }
55 }
56 }
Timer每隔100毫秒便調用一次Tick事件,在該事件中更新ProgressBar的目前進度。注意需要判斷ProgressBar的Value必須小于Maximum值時才去執行Performance()方法,否則會出現ProgressBar的Value大于Maximum的值而抛異常。根據BackgroundWorker的DoWork方法執行所需的時間長短不同,ProgressBar的進度可能會在BackgroundWorker執行具體操作完成之前到達100%,也可以沒有到達100%,是以在BackgroundWorker的RunWorkerCompleted事件中将ProgressBar的進度更新為100%,以確定進度在最後是一個完成的狀态。
如果你在應用程式中确實需要使用進度條來提示使用者背景程式在完成一個耗時較長的操作,而且你還希望進度條能盡量模拟出程式執行的步驟,而不是一個Marquee狀态,可以考慮使用Timer定時器控件。因為,有的時候我們确實很難評估一個執行過程到底需要多少步驟或者需要多長時間才能完成。
本文轉自Jaxu部落格園部落格,原文連結:http://www.cnblogs.com/jaxu/archive/2011/08/05/2128811.html,如需轉載請自行聯系原作者