---------------201504170911更新---------------
更新內容:刪除bgwUI新增的Start方法,改為通過new修飾符+可選參數的方式同時覆蓋基類(BackgroundWorker)的RunWorkerAsync有參和無參倆方法。所以執行任務仍舊使用熟悉的RunWorkerAsync即可,忘掉蹩腳的Start。在此要感謝園友【新的開始】在評論中的指點,非常感謝!
---------------20150416原文(已更新)---------------
適用環境:.net 2.0+的Winform項目
這是上一篇【分享帶等待窗體的任務執行器一枚】的姊妹篇,建議先看看那篇文章了解一下相關背景。這裡簡單介紹一下,兩個方案的共同目的都是在執行耗時任務時向用戶顯示一個模式窗體(我稱等待窗體),通過該窗體,任務可以向用戶報告執行進度,用戶也可以通過它干預任務的執行(也就是取消~如果任務允許被終止的話),等於就是在任務與用戶之間通過一個等待窗體來進行信息傳遞。這樣的需求應該是很常見的,注重用戶體驗的開發者都不可能讓用戶眼巴巴的面對一個卡死掉的界面,所以相信在類似場景中,大家都有各自的處理手段,例如異步執行任務,同時在業務窗體上弄個滾動條什麼的,比如這樣:
這樣的手段有的猿友可能已經形成了很完善的通用方案,比我這個好上百倍都不止(在此也懇請路過老鳥不吝分享自己的或自己知道的現成好方案),有的猿友則可能還是具體情況具體處理,沒有一個通用方案,而我在做的,就是把我的方案分享出來,讓還沒有類似輪子的猿友拿去後,經過簡單處理就能實現效果,同時,也希望得到老鳥的指點,不斷完善。
上一篇分享的是一個叫做WaitUI的執行器,可以執行任何方法,使用簡單。而這一篇分享的是一個叫做BackgroundWorkerUI的東東(下文簡稱bgwUI),看名字就知道它是基於BackgroundWorker(下文可能簡稱bgw)組件實現的,所以如果你更習慣bgw的使用方式,這個適合你。先看一下使用效果:
這裡只講區別,沒講到的表示與bgw一致,不熟悉bgw用法的猿友請MSDN。先看類圖:
從類圖可看出bgwUI是繼承於bgw的子類。
BackgroundWorkerUI.cs僅包含class BackgroundWorkerUI,它用到的WaitForm.cs請到上一篇文章取用,幫園子節約點空間~哈。
using System; using System.ComponentModel; using System.Windows.Forms; namespace AhDung.WinForm { /// <summary> /// 帶等待窗體的BackgroundWorker。報告進度用一組UI操作方法 /// </summary> public class BackgroundWorkerUI : BackgroundWorker { readonly IWaitForm waitForm;//等待窗體 Form activeForm;//等待窗體顯示前的活動窗體 bool formClosed;//指示等待窗體是否已被關閉 #region 一組操作等候窗體UI的屬性/方法 /// <summary> /// 獲取或設置進度描述 /// </summary> public string WorkMessage { get { if (waitForm.InvokeRequired) { return waitForm.Invoke(new Func<string>(() => waitForm.WorkMessage)) as string; } return waitForm.WorkMessage; } set { if (waitForm.InvokeRequired) { waitForm.BeginInvoke(new Action(() => waitForm.WorkMessage = value)); return; } waitForm.WorkMessage = value; } } /// <summary> /// 獲取或設置進度條可見性 /// </summary> public bool BarVisible { get { if (waitForm.InvokeRequired) { return Convert.ToBoolean(waitForm.Invoke(new Func<bool>(() => waitForm.BarVisible))); } return waitForm.BarVisible; } set { if (waitForm.InvokeRequired) { waitForm.BeginInvoke(new Action(() => waitForm.BarVisible = value)); return; } waitForm.BarVisible = value; } } /// <summary> /// 獲取或設置進度條動畫樣式 /// </summary> public ProgressBarStyle BarStyle { get { if (waitForm.InvokeRequired) { return (ProgressBarStyle)(waitForm.Invoke(new Func<ProgressBarStyle>(() => waitForm.BarStyle))); } return waitForm.BarStyle; } set { if (waitForm.InvokeRequired) { waitForm.BeginInvoke(new Action(() => waitForm.BarStyle = value)); return; } waitForm.BarStyle = value; } } /// <summary> /// 獲取或設置進度值 /// </summary> public int BarValue { get { if (waitForm.InvokeRequired) { return Convert.ToInt32(waitForm.Invoke(new Func<int>(() => waitForm.BarValue))); } return waitForm.BarValue; } set { if (waitForm.InvokeRequired) { waitForm.BeginInvoke(new Action(() => waitForm.BarValue = value)); return; } waitForm.BarValue = value; } } /// <summary> /// 獲取或設置進度條步進值 /// </summary> public int BarStep { get { if (waitForm.InvokeRequired) { return Convert.ToInt32(waitForm.Invoke(new Func<int>(() => waitForm.BarStep))); } return waitForm.BarStep; } set { if (waitForm.InvokeRequired) { waitForm.BeginInvoke(new Action(() => waitForm.BarStep = value)); return; } waitForm.BarStep = value; } } /// <summary> /// 使進度條步進 /// </summary> public void BarPerformStep() { if (waitForm.InvokeRequired) { waitForm.BeginInvoke(new Action(() => waitForm.BarPerformStep())); return; } waitForm.BarPerformStep(); } /// <summary> /// 獲取或設置進度條上限值 /// </summary> public int BarMaximum { get { if (waitForm.InvokeRequired) { return Convert.ToInt32(waitForm.Invoke(new Func<int>(() => waitForm.BarMaximum))); } return waitForm.BarMaximum; } set { if (waitForm.InvokeRequired) { waitForm.BeginInvoke(new Action(() => waitForm.BarMaximum = value)); return; } waitForm.BarMaximum = value; } } /// <summary> /// 獲取或設置進度條下限值 /// </summary> public int BarMinimum { get { if (waitForm.InvokeRequired) { return Convert.ToInt32(waitForm.Invoke(new Func<int>(() => waitForm.BarMinimum))); } return waitForm.BarMinimum; } set { if (waitForm.InvokeRequired) { waitForm.BeginInvoke(new Action(() => waitForm.BarMinimum = value)); return; } waitForm.BarMinimum = value; } } /// <summary> /// 獲取或設置取消任務的控件的可見性 /// </summary> public bool CancelControlVisible { get { if (waitForm.InvokeRequired) { return Convert.ToBoolean(waitForm.Invoke(new Func<bool>(() => waitForm.CancelControlVisible))); } return waitForm.CancelControlVisible; } set { if (waitForm.InvokeRequired) { waitForm.BeginInvoke(new Action(() => waitForm.CancelControlVisible = value)); return; } waitForm.CancelControlVisible = value; } } #endregion /// <summary> /// 初始化組件 /// </summary> public BackgroundWorkerUI() : this(new WaitForm()) { } /// <summary> /// 初始化組件並指定等待窗體 /// </summary> /// <param name="fmWait">等待窗體</param> public BackgroundWorkerUI(IWaitForm fmWait) { if (fmWait == null) { throw new WaitFormNullException(); } waitForm = fmWait; waitForm.UserCancelling += WaitForm_UserCancelling;//注冊用戶取消任務事件 } /// <summary> /// 開始執行後台操作 /// </summary> /// <param name="argument">要在DoWork事件處理程序中使用的參數</param> /// <remarks>通過可選參數可以同時覆蓋基類無參RunWorkerAsync,一石二鳥</remarks> public new void RunWorkerAsync(object argument = null) { Form f; activeForm = (f = Form.ActiveForm) != null && f.IsMdiContainer ? f.ActiveMdiChild : f;//記錄當時的活動窗體 waitForm.CancelControlVisible = this.WorkerSupportsCancellation; formClosed = false; base.RunWorkerAsync(argument); //這裡要判斷一下,極端情況下有可能還沒等ShowDialog,窗體就已經被關閉了 if (!formClosed) { waitForm.ShowDialog(); } } /// <summary> /// 用戶請求取消任務時 /// </summary> private void WaitForm_UserCancelling(object sender, EventArgs e) { this.CancelAsync(); } protected override void OnRunWorkerCompleted(RunWorkerCompletedEventArgs e) { waitForm.Hide(); formClosed = true; //上面Hide後,原活動窗體會在該方法完成後才會重新獲得焦點,所以必須加以干預讓原窗體現在就獲得焦點 //否則隨後的RunWorkerCompleted事件中彈出的模式窗體會有不正常的表現 if (activeForm != null && !activeForm.IsDisposed) { activeForm.Activate(); } base.OnRunWorkerCompleted(e); } //資源釋放 protected override void Dispose(bool disposing) { IDisposable form; if (disposing && (form = waitForm as IDisposable) != null) { form.Dispose(); } base.Dispose(disposing); } } } BackgroundWorkerUI.cs-----------------分隔線-----------------
下面的內容對於方案使用來說不是必須的,趕時間你可以先閃。
-文畢-