在Winform程序開發中,常常會遇到長時間任務處理的時候須要顯示等待窗口和進度條的狀況,若是直接在主窗口UI線程上執行,則窗口會假死和空白,用戶體驗很不友好。因此相信你們在實踐中都會常常實現本身的等待窗口和進度信息顯示,這也是一個我常常在項目開發中使用的小工具,方便地引入新項目中使用,特此與你們分享,並但願你們提出建議,一塊兒交流多線程開發中的經驗。多線程
既然要在處理任務的時候要保持主窗口和等待窗口的「活動」狀態,天然就想到了多線程和異步操做。.NET Framework裏已經自帶了後臺工做線程對象BackgroundWorker和進度條控件,因此實現起來並不難。這個自定義的等待窗口的好處就是已經把經常使用的顯示控件和接口實現好了,同時能夠根據須要靈活修改和進一步美化,便於移植到不一樣項目中。異步
實現思路就是定義一個窗體,用來顯示進度和其它信息,供主窗口來調用。既然等待窗口只是用來顯示,因此它在調用的時候用Form.Show()方法,同時將它定義爲單例對象,便於不一樣的代碼段來共同操做它。工具
主要代碼摘錄以下:ui
1.等待窗口的主要定義this
1 /// <summary> 2 /// 返回單個實例對象 3 /// </summary> 4 /// <returns></returns> 5 public static WaitWindow GetInstance() 6 { 7 if( instance == null || instance.IsDisposed) 8 { 9 instance = new WaitWindow(); 10 } 11 else 12 { 13 instance.label_percent.Text = ""; 14 } 15 return instance; 16 } 17 18 /// <summary> 19 ///請求終止當前系統正在處理的事務 20 /// </summary> 21 public event System.EventHandler OnProcessAbort; 22 23 /// <summary> 24 /// 修改進度條窗口標題 25 /// </summary> 26 /// <returns></returns> 27 public string Caption 28 { 29 set { this.Text = value; } 30 } 31 /// <summary> 32 /// 修改提示信息 33 /// </summary> 34 /// <returns></returns> 35 public string Title 36 { 37 set { this.label_prompt.Text = value; } 38 } 39 /// <summary> 40 /// 修改進度信息 41 /// </summary> 42 public string ProgressInfo 43 { 44 set { this.label_percent.Text = value; } 45 } 46 47 /// <summary> 48 /// 是否開啓取消按鈕的可用狀態(默認開啓) 49 /// </summary> 50 public bool IsCancelEnable 51 { 52 set { this.btn_cancel.Enabled = value; } 53 } 54 55 /// <summary> 56 /// 設置/讀到是否顯示進度條(默認關閉,如開啓,則要傳遞Value以刷新進度條) 57 /// </summary> 58 public bool IsProgressBarVisible 59 { 60 set { this.progressBar.Visible = value; } 61 get { return this.progressBar.Visible; } 62 } 63 /// <summary> 64 /// 設置/讀取當前進度條value 65 /// </summary> 66 public int ProgressValue 67 { 68 set { this.progressBar.Value = value; } 69 get { return this.progressBar.Value; } 70 } 71 /// <summary> 72 /// 設置/讀取進度條的最大值(默認100) 73 /// </summary> 74 public int ProgressMaxValue 75 { 76 set { this.progressBar.Maximum = value; } 77 get { return this.progressBar.Maximum; } 78 }
2.主窗口的調用和實現spa
1 //用戶是否取消當前任務 2 private bool isUserCancel = false; 3 4 private void btnDoWork_Click(object sender, EventArgs e) 5 { 6 isUserCancel = false; 7 //顯示進度窗口 8 WaitWindow waitx = WaitWindow.GetInstance(); 9 waitx.IsProgressBarVisible = true; //開啓進度條 10 waitx.ProgressMaxValue = 10; //進度條最大value(結束值) 11 waitx.OnProcessAbort += new EventHandler(waitx_OnProcessAbort); //用戶取消事件 12 waitx.Show(); 13 //使用另外一線程進行任務處理 14 Thread t = new Thread(new ThreadStart(this.DoLongTimeTask)); 15 t.Start(); 16 } 17 18 void waitx_OnProcessAbort(object sender, EventArgs e) 19 { 20 isUserCancel = true; 21 } 22 //通知進度代理 23 delegate void NotifyProgressHandler(int progressValue); 24 25 //進度通知處理方法 26 void NotifyProgress(int v) 27 { 28 WaitWindow win = WaitWindow.GetInstance(); 29 win.ProgressValue = v; //當前進度 30 string msg = "已完成: " + v + "/" + win.ProgressMaxValue; 31 win.ProgressInfo = msg; 32 } 33 34 //執行長時間任務處理 35 void DoLongTimeTask() 36 { 37 int i = 1; 38 //由於有可能用戶會取消,要隨時判斷取消標記 39 while (i < 11 && !isUserCancel) 40 { 41 Thread.Sleep(1000); //耗時工做 42 Console.WriteLine("current value:" + i); 43 //通知等待窗口當前進度(BeginInvoke) 44 this.BeginInvoke(new NotifyProgressHandler(this.NotifyProgress), i); 45 i++; 46 } 47 //任務處理完畢 48 if (this.InvokeRequired) 49 this.Invoke(new MethodInvoker(this.EndTask)); 50 else 51 this.EndTask(); 52 } 53 54 //任務處理結束(須要關閉等待窗口以及告知處理結果等) 55 void EndTask() 56 { 57 WaitWindow win = WaitWindow.GetInstance(); 58 win.Close(); 59 if (isUserCancel) 60 MessageBox.Show("任務處理已被用戶取消,即將退出. ", "任務處理", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); 61 else 62 MessageBox.Show("任務處理已經完成.", "任務處理", MessageBoxButtons.OK, MessageBoxIcon.Information); 63 }
運行效果以下圖:線程
代碼下載:WaitWindowApp代理
歡迎進一步交流:)code