当后台任务进行时,需要在主程序给个延迟以保证后台在刷新进度显示时有足够时间显示出来
所以要在主进程里走进度,而不是BackgroundWorker的通知
举例如下:
1. 声明一个后台任务
readonly BackgroundWorker bgWorker;2. 设置任务
/* ---------- 设置线程任务 ---------- */ bgWorker = new BackgroundWorker { // 开启进度报告 WorkerReportsProgress = true, // 开启异步取消 WorkerSupportsCancellation = true }; bgWorker.DoWork += BgWorker_Start; bgWorker.ProgressChanged += BgWorker_Progress; bgWorker.RunWorkerCompleted += BgWorker_Completed;3. 实现线程任务和线程方法
#region 线程方法 /// <summary> /// 启动线程 /// </summary> /// <param name="start"></param> /// <param name="completed"></param> /// <param name="progress"></param> /// <param name="cancel"></param> public void Run(Action start, Action completed, Action<int> progress = null, Action cancel = null) { StartWork = start; CompletedWork = completed; ProgressWork = progress; CancelWork = cancel; if (!bgWorker.IsBusy) { bgWorker.RunWorkerAsync(); } else { Debug.WriteLine("当前任务正忙"); } } /// <summary> /// 取消线程 /// </summary> public void Cancel() { if (bgWorker.IsBusy) { bgWorker.CancelAsync(); } else { Debug.WriteLine("没有正在执行的任务"); } } /// <summary> /// 报告进度 /// </summary> /// <param name="progress"></param> public void ReportProgress(int progress) { bgWorker.ReportProgress(progress); } #endregion #region 线程任务 /// <summary> /// 后台操作任务 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void BgWorker_Start(object sender, DoWorkEventArgs e) { PercentText = "正在启动..."; StartWork?.Invoke(); work(bgWorker); } /// <summary> /// 后台操作进行时 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void BgWorker_Progress(object sender, ProgressChangedEventArgs e) { PercentText = $"正在启动 {e.ProgressPercentage}%"; ProgressWork?.Invoke(e.ProgressPercentage); } /// <summary> /// 后台操作完成 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void BgWorker_Completed(object sender, RunWorkerCompletedEventArgs e) { // 执行主进程回调 Application.Current.Dispatcher.BeginInvoke(new Action(delegate { CompletedWork?.Invoke(); })); } #endregion4. 主进程调用线程执行百分比
/// <summary> /// 进度显示 /// </summary> /// <param name="bk"></param> /// <returns></returns> static void work(BackgroundWorker bk) { for (int i = 0; i < 100; i++) { if (bk.CancellationPending) { bk.ReportProgress(i, $"当前进度: {i}%, 操作被用户中断"); return; } bk.ReportProgress(i); /** * 必须在主程序暂停 * 后台程序不能加延迟,否则后台程序就不会更新进度了 */ Thread.Sleep(10); } }注意,上面的work是实际的进度百分比的显示过程,在后台程序的doWork中调用
1.线程的执行是以BgWorker_Start开始, 在BgWorker_Start中又有work执行任务
2.在work中调用线程报告时会执行BgWorker_Progress, 而每次work调用后会有一个10毫秒的延迟,以保证线程报告可以执行完毕
3.在线程报告中,不应该有任何阻塞