很多時候,我們需要在窗體中執行一些耗時比較久的任務。比如:循環處理某些文件,發送某些消息等。。。
單純的依靠狀態欄,用戶體驗不佳,按下功能按鈕后得不到有效的提醒,小白用戶絕對會電話給你說“我點了以后就沒反應了...”。
因此,對於響應時間可能超過5秒以上的事件,有必要增加一個顯眼的提示框(在屏幕中央,最好有動圖,如果有需要的話還可以設置為模態)。
此實現大體分三部分(重點在於使用BGWK解決UI阻塞的問題):
1、設計好提醒頁面(一個轉圈圈的動圖Image,一個狀態文字Label,再加一個進度條):
如果不需要動圖,則這個窗體無需編寫代碼。
2、顯示這個窗體的代碼,目前放在基類窗體中被子類窗體繼承。

1 #region 顯示應用程序作業狀態 2 /// <summary> 3 /// 后台作業線程定義模板類 4 /// </summary> 5 protected class BgwkDef 6 { 7 public BackgroundWorker TagBgwk; 8 public Action RunningAction; 9 public int TProgMinimum = 0; 10 public int TProgStep = 1; 11 public int TProgMaximum = 100; 12 public string RunningStatus; 13 } 14 15 /// <summary> 16 /// 以指定的定義開始一個線程運行作業任務 17 /// </summary> 18 /// <param name="sBgwkDef"></param> 19 protected void BeginBgwork(BgwkDef sBgwkDef) 20 { 21 if (frmStatus == null) 22 { 23 frmStatus = new FrmStatus(); 24 } 25 if (frmStatus != null) 26 { 27 frmStatus.ProgMain.Minimum = sBgwkDef.TProgMinimum; 28 frmStatus.ProgMain.Step = sBgwkDef.TProgStep; 29 frmStatus.ProgMain.Maximum = sBgwkDef.TProgMaximum; 30 frmStatus.TopLevel = false; 31 frmStatus.Parent = this; 32 frmStatus.Show(); 33 frmStatus.BringToFront(); 34 frmStatus.Left = (this.Width - frmStatus.Width) / 2; 35 frmStatus.Top = (this.Height - frmStatus.Height) / 2 - 90; 36 } 37 if (sBgwkDef.RunningAction == null) 38 { 39 MyMsg.Warning("系統后台任務必須指定作業方法,請檢查!"); 40 return; 41 } 42 43 BackgroundWorker tagBgwk = sBgwkDef.TagBgwk ?? new BackgroundWorker(); 44 tagBgwk.WorkerSupportsCancellation = true; 45 tagBgwk.WorkerReportsProgress = true; 46 tagBgwk.DoWork -= BgwkBase1_DoWork; 47 tagBgwk.DoWork += BgwkBase1_DoWork; 48 tagBgwk.ProgressChanged -= BgwkBase1_ProgressChanged; 49 tagBgwk.ProgressChanged += BgwkBase1_ProgressChanged; 50 tagBgwk.RunWorkerCompleted -= BgwkBase1_RunWorkerCompleted; 51 tagBgwk.RunWorkerCompleted += BgwkBase1_RunWorkerCompleted; 52 tagBgwk.RunWorkerAsync(sBgwkDef.RunningAction); 53 } 54 55 /// <summary> 56 /// 取消后台任務的當前作業 57 /// </summary> 58 /// <param name="tagBgwk"></param> 59 protected void CancelBgwork(BackgroundWorker tagBgwk) 60 { 61 tagBgwk.CancelAsync(); 62 } 63 64 /// <summary> 65 /// 在此事件中調用工作方法 66 /// </summary> 67 /// <param name="sender"></param> 68 /// <param name="e"></param> 69 protected void BgwkBase1_DoWork(object sender, DoWorkEventArgs e) 70 { 71 ((Action)e.Argument).Invoke(); 72 } 73 74 /// <summary> 75 /// 當后台任務運行進行進度報告時在狀態窗口中顯示狀態 76 /// </summary> 77 /// <param name="sender"></param> 78 /// <param name="e"></param> 79 protected void BgwkBase1_ProgressChanged(object sender, ProgressChangedEventArgs e) 80 { 81 if (frmStatus != null) 82 { 83 frmStatus.ProgMain.Value = e.ProgressPercentage > frmStatus.ProgMain.Maximum ? frmStatus.ProgMain.Maximum : e.ProgressPercentage; 84 frmStatus.ProgMain.PerformStep(); 85 frmStatus.LabMessage.Text = e.UserState.ToString(); 86 frmStatus.LabMessage.Refresh(); 87 } 88 SetMainStatus(e.UserState.ToString()); 89 } 90 91 /// <summary> 92 /// 任務結束后(e.ProgressPercentage到100)關閉狀態窗口 93 /// </summary> 94 /// <param name="sender"></param> 95 /// <param name="e"></param> 96 protected void BgwkBase1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 97 { 98 if (e.Cancelled) 99 { 100 } 101 if (frmStatus != null) 102 { 103 frmStatus.Close(); 104 frmStatus = null; 105 } 106 } 107 #endregion
3、調用第2步的顯示方法的代碼(實際工作場合)。
private void CmdExport_Click(object sender, EventArgs e) { //創建或匹配一個BackgroundWorker,初始化一個耗時任務 BackgroundWorker bgwk = new BackgroundWorker(); BgwkDef bgwkDef = new BgwkDef() { RunningAction = delegate () { ExportIvoice(bgwk); }, TagBgwk = bgwk }; BeginBgwork(bgwkDef); } //耗時比較久的工作任務方法 private void ExportIvoice(BackgroundWorker bgwk) { bgwk.ReportProgress(1, "正在嘗試導出到EXCEL..."); //打開Excel等操作 //各種操作...... if ("出錯了") { CancelBgwork(bgwk);//取消任務 MyMsg.Exclamation("開啟報表文件失敗,請檢查!"); return; } //繼續運行...... //最后完成任務 bgwk.ReportProgress(100, "導出成功!"); return; }
這樣,比較簡單的就完成了一個友好提示功能。