.net開發筆記(十八) winform中的等待框

周見智發表於2013-12-04

      winform中很多工是需要在後臺執行緒(或類似)中完成的,也就是說,經常容易涉及到UI介面與後臺工作執行緒之間的互動。比如UI介面控制後臺工作的執行(啟動、暫停、停止等),後臺工作進度在UI介面上的顯示。前兩天一個員工在UI執行緒中訪問資料庫,剛開始資料庫在區域網中,沒感覺到什麼,後來將資料庫移到了外網,發現問題來了,至於問題原因想必諸位都知曉,更詳細的解釋請參考本系列部落格(四)。後將這方面的東西整理了一下,如下:

執行後臺任務時,UI介面應該怎麼做?大概分兩種情況:(我自己隨便給取的名字)

(1)一種是模式等待

也就說,後臺工作沒有完成之前,UI介面不允許操作,如下圖:

圖1

如上圖所示,紅色箭頭表示後臺跟UI介面的互動。

(2)一種是非模式等待

後臺工作沒完成之前,UI介面可以操作,這個類似檔案複製出現的資訊框,如下圖:

圖2

如上圖所示,紅色箭頭表示後臺與UI介面的互動。

以上是兩種情況,以及對應的結構圖,我做了一個Demo,包含兩種等待窗體,一種即為“模式等待窗體”,另一種為“非模式等待窗體”。原始碼在文章結束後有下載地址。先來分別看一下兩者的程式碼:

(1)模式等待窗體

 1 public partial class frmWait : Form
 2     {
 3         bool _run = true;
 4         public frmWait()
 5         {
 6             InitializeComponent();
 7         }
 8         public object DoWait(object param)
 9         {
10             List<string> list = new List<string>();
11             int count = (int)param;
12             progressBar1.Maximum = count;
13 
14             //---------------------以下程式碼片段可以使用執行緒代替
15             ((Action)delegate()
16             {
17                 System.Threading.Thread.Sleep(1000);
18 
19                     for (int i = 0; i < count; ++i) //耗時操作
20                     {
21                         if (_run)
22                         {
23                             string s = DateTime.Now.ToLongTimeString();
24                             list.Add(s);
25                             this.Invoke((Action)delegate()
26                             {
27                                 if (!IsDisposed)
28                                 {
29                                     progressBar1.Value = i;
30                                     label1.Text = "正在載入字串 \"" + s + "\"";
31                                 }
32                             });
33                             System.Threading.Thread.Sleep(500);
34                         }
35                         else
36                         {
37                             break;
38                         }
39                     }
40 
41             }).BeginInvoke(new AsyncCallback(OnAsync), null);  //非同步執行後臺工作
42             //------------------------
43 
44             ShowDialog(); //UI介面等待
45             return list; //後臺工作執行完畢 可以使用結果
46         }
47         private void OnAsync(IAsyncResult ar)
48         {
49             if (_run) //後臺工作正常結束
50                 DialogResult = DialogResult.OK;
51         }
52         private void frmWait_Load(object sender, EventArgs e)
53         {
54 
55         }
56 
57         private void button1_Click(object sender, EventArgs e)
58         {
59             _run = false; //UI介面控制後臺結束
60             DialogResult = DialogResult.Cancel;
61         }
62 }
View Code

如上程式碼所示,後臺任務很簡單,就是返回指定數目(param)個字串,存放在一個list中,使用frmWait也很簡單:

1  using (frmWait frmw = new frmWait())
2             {
3                 List<string> list = frmw.DoWait(50) as List<string>; //彈出模式等待窗體 實時更新顯示後臺工作進度 後臺工作結束後  等待窗體消失  UI執行緒繼續執行...
4                 MessageBox.Show("載入字串 " + list.Count + "");
5             }
View Code

(2)非模式等待窗體

 1  public partial class frmNoWait : Form
 2     {
 3         bool _run = true;
 4         public frmNoWait()
 5         {
 6             InitializeComponent();
 7         }
 8         private void OnAsync(IAsyncResult ar)
 9         {
10             // ar.AsyncState as List<string> 後臺工作執行完畢的結果
11 
12             if (_run) //後臺工作正常結束
13                 this.Invoke((Action)delegate()
14                 {
15                     Close();
16                 });
17         }
18         public void DoNoWait(int param)
19         {
20             List<string> list = new List<string>();
21             int count = (int)param;
22             progressBar1.Maximum = count;
23 
24             //-----------------------以下程式碼片段 可以使用執行緒代替
25             ((Action)delegate()
26             {
27                 try
28                 {
29                     System.Threading.Thread.Sleep(1000);
30                     for (int i = 0; i < count; ++i) //耗時操作
31                     {
32                         if (_run)
33                         {
34                             string s = DateTime.Now.ToLongTimeString();
35                             list.Add(s);
36                             this.Invoke((Action)delegate()
37                             {
38                                 if (!IsDisposed)
39                                 {
40                                     progressBar1.Value = i;
41                                     label1.Text = "正在載入字串 \"" + s + "\"";
42                                 }
43                             });
44                             System.Threading.Thread.Sleep(500);
45                         }
46                         else
47                         {
48                             break;
49                         }
50                     }
51                 }
52                 catch
53                 {
54 
55                 }
56             }).BeginInvoke(new AsyncCallback(OnAsync), list); //非同步執行後臺工作
57             //----------------------------
58 
59             Show();//UI介面不用等待
60         }
61         private void frmNoWait_Load(object sender, EventArgs e)
62         {
63             Text += (" " + Form1.index++ + "");
64         }
65 
66         private void button1_Click(object sender, EventArgs e)
67         {
68             Close();
69         }
70         protected override void OnFormClosing(FormClosingEventArgs e)
71         {
72             base.OnFormClosing(e);
73             _run = false; //UI介面控制後臺結束
74         }
75     }
View Code

如上程式碼所示,後臺工作開始後,彈出一個非模式對話方塊,UI介面可以繼續操作,也就是說,你可以出現多個frmNoWait窗體,使用很簡單,如下:

1 frmNoWait frmnw = new frmNoWait();
2 frmnw.DoNoWait(50);   //彈出窗體
3 //UI介面繼續...
View Code

至於怎麼通知UI介面,後臺工作結束了,你可以在OnAsync中完成這個功能。

最後上幾張截圖:

圖3

圖4

原始碼下載地址:https://files.cnblogs.com/xiaozhi_5638/ProgressForm.rar

希望有幫助!

相關文章