使用多線程制作簡單的Winform進度條


轉自:http://www.cnblogs.com/zzy0471/archive/2010/12/12/1903602.html

在WinForm開發中,在處理大量數據時不免會有耗時較長的操作,如果將這些操作放在主線程里,軟件界面會有較長時間的“無響應”,降低了用戶體驗,常用的解決方式是加上進度條。

實現思路


使用BackgroundWorker(已經封裝好的線程工具)控件在后台線程執行費時的操作,在主線程中打開一個進度條窗體顯示進度。

實現步驟


第0步:創建一個具有進度條的窗體,以顯示進度

新建窗體ProcessForm,設置屬性FormBorderStyle為None,添加一個ProcessBar控件,如下圖所示:

進度條窗體

PrcessBar的Style屬性設置為MarQuee。在ProcessForm添加如下公共屬性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/// <summary>
/// 設置提示信息
/// </summary>
public  string  MessageInfo
{
     set  { this .labelInfor.Text = value; }
}
 
/// <summary>
/// 設置進度條顯示值
/// </summary>
public  int  ProcessValue
{
     set  { this .progressBar1.Value = value; }
}
 
/// <summary>
/// 設置進度條樣式
/// </summary>
public  ProgressBarStyle ProcessStyle
{
     set  { this .progressBar1.Style = value; }
}

第1步:創建進度條管理類ProcessOperator

在該類中添加如下字段:

1
2
private  BackgroundWorker _backgroundWorker; //后台線程
  private  ProcessForm _processForm; //進度條窗體

添加如下公共屬性、方法和事件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#region 公共方法、屬性、事件
 
         /// <summary>
         /// 后台執行的操作
         /// </summary>
         public  Action BackgroundWork { get ; set ; }
 
         /// <summary>
         /// 設置進度條顯示的提示信息
         /// </summary>
         public  string  MessageInfo
         {
             set  { _processForm.MessageInfo = value; }
         }
 
         /// <summary>
         /// 后台任務執行完畢后事件
         /// </summary>
         public  event  EventHandler<EventArgs> BackgroundWorkerCompleted;
 
         /// <summary>
         /// 開始執行
         /// </summary>
         public  void  Start()
         {
             _backgroundWorker.RunWorkerAsync();
             _processForm.ShowDialog();
         }
 
         #endregion

其中,屬性BackgroundWork可以指向一個無參數的方法,這里(客戶端代碼)用來指向要在后台執行的費時操作方法,在_backgroundWorker的事件DoWork中調用該委托指向的方法

1
2
3
4
5
6
7
8
//后台執行的操作
        private  void  _backgroundWorker_DoWork( object  sender, DoWorkEventArgs e)
        {
            if  (BackgroundWork != null )
            {
                BackgroundWork();
            }
        }

public void Start() 為啟動進度條的方法,調用該方法后,會在后台線程(_backgroundWorker.RunWorkerAsync(); )中執行費時操作(DoWork事件中的委托指向的方法)。同時,_processForm.ShowDialog()方法負責打開進度條窗體。

當后台方法執行完畢后,會觸發backgroundWorker的RunWorkerCompleted事件,在該事件中關閉進度條窗體

1
2
3
4
5
6
7
8
9
10
11
12
//操作進行完畢后關閉進度條窗體
        private  void  _backgroundWorker_RunWorkerCompleted( object  sender, RunWorkerCompletedEventArgs e)
        {
            if  (_processForm.Visible == true )
            {
                _processForm.Close();
            }
            if  ( this .BackgroundWorkerCompleted != null )
            {
                this .BackgroundWorkerCompleted( null , null );
            }
        }

以下是完整的ProcessOperator類代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/*
  * author:Joey Zhao
  * date:2010-11-30
  * describe:進度條,該類可以在后台線程處理一些費時操作,並顯示進度條,進度條並未真實顯示數據進度
  * 僅僅是告訴用戶程序還活着,有待加強。使用方法:
  * 1, 實例化一個ProcessOperator對象;
  * 2,賦值BackgroundWork(類型為一個無參數無返回值的委托)屬性為要在后台執行的方法(無參數無返回值的方法)
  * 3,調用Start方法開始執行
  * 4, 在事件BackgroundWorkerCompleted中執行后台任務完成后的操作
  */
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;
using  System.ComponentModel;
 
namespace  Sasp.Client.PublicUnits.Process
{
     public  class  ProcessOperator
     {
         private  BackgroundWorker _backgroundWorker; //后台線程
         private  ProcessForm _processForm; //進度條窗體
 
         public  ProcessOperator()
         {
             _backgroundWorker = new  BackgroundWorker();
             _processForm = new  ProcessForm();
             _backgroundWorker.DoWork += new  DoWorkEventHandler(_backgroundWorker_DoWork);
             _backgroundWorker.RunWorkerCompleted += new  RunWorkerCompletedEventHandler(_backgroundWorker_RunWorkerCompleted);
         }
 
         //操作進行完畢后關閉進度條窗體
         private  void  _backgroundWorker_RunWorkerCompleted( object  sender, RunWorkerCompletedEventArgs e)
         {
             if  (_processForm.Visible == true )
             {
                 _processForm.Close();
             }
             if  ( this .BackgroundWorkerCompleted != null )
             {
                 this .BackgroundWorkerCompleted( null , null );
             }
         }
 
         //后台執行的操作
         private  void  _backgroundWorker_DoWork( object  sender, DoWorkEventArgs e)
         {
             if  (BackgroundWork != null )
             {
                 BackgroundWork();
             }
         }
 
         #region 公共方法、屬性、事件
 
         /// <summary>
         /// 后台執行的操作
         /// </summary>
         public  Action BackgroundWork { get ; set ; }
 
         /// <summary>
         /// 設置進度條顯示的提示信息
         /// </summary>
         public  string  MessageInfo
         {
             set  { _processForm.MessageInfo = value; }
         }
 
         /// <summary>
         /// 后台任務執行完畢后事件
         /// </summary>
         public  event  EventHandler<EventArgs> BackgroundWorkerCompleted;
 
         /// <summary>
         /// 開始執行
         /// </summary>
         public  void  Start()
         {
             _backgroundWorker.RunWorkerAsync();
             _processForm.ShowDialog();
         }
 
         #endregion
     }
}

第2步:客戶端代碼調用

1
2
3
4
PercentProcessOperator p = new  PercentProcessOperator();
           p.BackgroundWork = this .LoadData;
           p.BackgroundWorkerCompleted += new  EventHandler<EventArgs>(p_BackgroundWorkerCompleted);
           p.Start();

擴展:實時報告后台處理進度

將_backgroundWorker的屬性WorkerReportsProgress設置為ture;這樣就可以添加backgroundWorker的ProgressChanged事件了(該事件在調用方法_backgroundWorker.ReportProgress(int p)時觸發。

1
2
3
4
5
6
//顯示進度
         private  void  _backgroundWorker_ProgressChanged( object  sender, ProgressChangedEventArgs e)
         {
             _processForm.MessageInfo = "已完成:" +e.ProgressPercentage.ToString()+ "%" ;
             _processForm.ProcessValue = e.ProgressPercentage;
         }

_backgroundWorker.ReportProgress(int p)方法應該是在后台執行操作中調用,只有后台執行的操作才知道自己的完成進度。可以使用一個委托參數,客戶端代碼調用該委托設置進度,而該委托指向的方法設置為_backgroundWorker.ReportProgress(int p)即可。以下代碼是帶有進度預報的實現:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/*
  * author:Joey Zhao
  * date:2010-12-1
  * describe:帶百分比的進度條,使用方法:
  * 1, 實例化一個ProcessOperator對象;
  * 2,賦值BackgroundWork(類型為一個參數,無返回值的委托,其中參數是一個具有一個int類型參數無返回值的委托,用來預報進度)屬性為要在后台執行的方法,詳見TestForm中的示例
  * 3,調用Start方法開始執行
  * 4, 在事件BackgroundWorkerCompleted中執行后台任務完成后的操作
  */
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;
using  System.ComponentModel;
 
namespace  Sasp.Client.PublicUnits.Process
{
     public  class  PercentProcessOperator
     {
         private  BackgroundWorker _backgroundWorker; //后台線程
         private  ProcessForm _processForm; //進度條窗體
 
         public  PercentProcessOperator()
         {
             _processForm = new  ProcessForm();
             _processForm.ProcessStyle = System.Windows.Forms.ProgressBarStyle.Continuous;
             _backgroundWorker = new  BackgroundWorker();
             _backgroundWorker.WorkerReportsProgress = true ;
             _backgroundWorker.DoWork += new  DoWorkEventHandler(_backgroundWorker_DoWork);
             _backgroundWorker.RunWorkerCompleted += new  RunWorkerCompletedEventHandler(_backgroundWorker_RunWorkerCompleted);
             _backgroundWorker.ProgressChanged += new  ProgressChangedEventHandler(_backgroundWorker_ProgressChanged);
         }
 
         //顯示進度
         private  void  _backgroundWorker_ProgressChanged( object  sender, ProgressChangedEventArgs e)
         {
             _processForm.MessageInfo = "已完成:" +e.ProgressPercentage.ToString()+ "%" ;
             _processForm.ProcessValue = e.ProgressPercentage;
         }
 
         //操作進行完畢后關閉進度條窗體
         private  void  _backgroundWorker_RunWorkerCompleted( object  sender, RunWorkerCompletedEventArgs e)
         {
             if  (_processForm.Visible == true )
             {
                 _processForm.Close();
             }
             if  ( this .BackgroundWorkerCompleted != null )
             {
                 this .BackgroundWorkerCompleted( null , null );
             }
         }
 
         //后台執行的操作
         private  void  _backgroundWorker_DoWork( object  sender, DoWorkEventArgs e)
         {
             if  (BackgroundWork != null )
             {
                 BackgroundWork( this .ReportPercent);
             }
         }
 
         #region 公共方法、屬性、事件
 
         /// <summary>
         /// <para>后台執行的操作,參數為一個參數為int型的委托;
         /// 在客戶端要執行的后台方法中可以使用Action&lt;int&gt;預報完成進度,如:
         /// <example>
         /// <code>
         /// PercentProcessOperator o = new PercentProcessOperator();
         /// o.BackgroundWork = this.DoWord;
         ///
         /// private void DoWork(Action&lt;int&gt; Report)
         /// {
         ///     Report(0);
         ///     //do soming;
         ///     Report(10);
         ///     //do soming;
         ///     Report(50);
         ///     //do soming
         ///     Report(100);
         /// }
         /// </code>
         /// </example></para>
         /// </summary>
         public  Action<Action< int >> BackgroundWork { get ; set ; }
 
         /// <summary>
         /// 后台任務執行完畢后事件
         /// </summary>
         public  event  EventHandler<EventArgs> BackgroundWorkerCompleted;
 
         /// <summary>
         /// 開始執行
         /// </summary>
         public  void  Start()
         {
             _backgroundWorker.RunWorkerAsync();
             _processForm.ShowDialog();
         }
 
         #endregion
 
         //報告完成百分比
         private  void  ReportPercent( int  i)
         {
             if  (i >=0 && i<=100)
             {
                 _backgroundWorker.ReportProgress(i);
             }
         }
     }
}
1
  

還是把Demo傳來了,原來的代碼找不到了,今天現寫了個例子,O(∩_∩)O哈哈~ 點擊下載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM