在Winform程序開發中,經常會遇到長時間任務處理的時候需要顯示等待窗口和進度條的情況,如果直接在主窗口UI線程上執行,則窗口會假死和空白,用戶體驗很不友好。所以相信大家在實踐中都會經常實現自己的等待窗口和進度信息顯示,這也是一個我經常在項目開發中使用的小工具,方便地引入新項目中使用,特此與大家分享,並希望大家提出建議,一起交流多線程開發中的經驗。
既然要在處理任務的時候要保持主窗口和等待窗口的“活動”狀態,自然就想到了多線程和異步操作。.NET Framework里已經自帶了后台工作線程對象BackgroundWorker和進度條控件,所以實現起來並不難。這個自定義的等待窗口的好處就是已經把常用的顯示控件和接口實現好了,同時可以根據需要靈活修改和進一步美化,便於移植到不同項目中。
實現思路就是定義一個窗體,用來顯示進度和其它信息,供主窗口來調用。既然等待窗口只是用來顯示,所以它在調用的時候用Form.Show()方法,同時將它定義為單例對象,便於不同的代碼段來共同操作它。
主要代碼摘錄如下:
1.等待窗口的主要定義
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.主窗口的調用和實現
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
歡迎進一步交流:)