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


      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

源碼下載地址:http://files.cnblogs.com/xiaozhi_5638/ProgressForm.rar

希望有幫助!


免責聲明!

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



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