C# 在Winform设计一个耗时较久的任务在后台执行时的状态提示窗口

很多时候,我们需要在窗体中执行一些耗时比较久的任务。比如:循环处理某些文件,发送某些消息等。。。

单纯的依靠状态栏,用户体验不佳,按下功能按钮后得不到有效的提醒,小白用户绝对会电话给你说“我点了以后就没反应了...”。

因此,对于响应时间可能超过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
View Code

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;
        } 

 

这样,比较简单的就完成了一个友好提示功能。

posted @ 2018-09-30 17:03  ROTA  阅读(4615)  评论(1编辑  收藏  举报