你的位置:首页 > 软件开发 > ASP.net > 【C#】分享带等待窗体的任务执行器一枚

【C#】分享带等待窗体的任务执行器一枚

发布时间:2015-04-15 16:00:37
适用环境:.net 2.0+的Winform项目。先解释一下我所谓的【带等待窗体的任务执行器】是个什么鬼,就是可以用该类执行任意耗时方法(下文将把被执行的方法称为任务或任务方法),执行期间会显示一个模式等待窗体,让用户知道任务正在得到执行,程序并没有卡死。先看一下效果:功能:等待 ...

适用环境:.net 2.0+的Winform项目。

先解释一下我所谓的【带等待窗体的任务执行器】是个什么鬼,就是可以用该类执行任意耗时方法(下文将把被执行的方法称为任务任务方法),执行期间会显示一个模式等待窗体,让用户知道任务正在得到执行,程序并没有卡死。先看一下效果:

【C#】分享带等待窗体的任务执行器一枚

功能:

  • 等待窗体可以使用执行器自带的默认窗体(就上图的样子),嫌丑你也可以使用自己精心设计的窗体,甚至基于Devpress、C1等第三方漂亮窗体打造也是完全可以的
  • 在任务中可以更新等待窗体上的Label、ProgressBar之类的控件以提供进度反馈。懒得反馈的话,就默认“请稍候...”+Marquee式滚动
  • 如果任务允许被终止,用户可以通过某些操作终止任务执行(例如点击上图中的【取消】按钮);如果不允许,你可以把取消按钮隐藏了,或者在任务中不响应用户的终止请求就好
  • 任务的执行结果(包括ref/out参数)、是否出现异常、是否被取消等情况都可以得到

原理:

  • 调用任务所属委托的BeginInvoke,让任务在后台get='_blank'>线程执行,随即在UI线程(通常就是主线程)调用等待窗体的ShowDialog弹出模式窗体,让用户知道任务正在执行的同时阻止用户进行其他操作。由于任务和等待窗体分别在不同的线程跑,所以等待窗体不会被卡住
  • 任务执行期间可以通过执行器提供的一组属性和方法操作等待窗体上的控件,这组属性和方法内部是通过调用等待窗体的Invoke或BeginInovke对控件进行操作,实现跨线程访问控件
  • 任务执行期间用户可以通过点击等待窗体上的【取消】按钮(如果你让它显示的话)或点击右上角关闭按钮发出终止任务的请求(等待窗体会拦截关闭操作),其结果是执行器的UserCancelling属性会置为true,所以在任务中可以访问该属性得知用户是否请求了取消操作,如果你同意终止的话,需设置执行器的Cancelled=true,并随即return出任务方法
  • 任务执行完后(无论成功、异常、取消)会自动进入异步回调方法,回调方法中会首先访问Cancelled获知任务是否已取消,如果已取消,则直接return出回调方法;如果未取消,则调用任务所属委托的EndInvoke得到任务执行结果或异常。最后不管取消与否,finally块中会设置等待窗体的DialogResult属性,以确保关闭等待窗体
  • 等待窗体关闭后,执行器会继续执行ShowDialog后面的语句。如果任务已取消,则抛出特定异常报告调用者;如果任务存在异常,则抛出该异常;以上情况都不存在的话,返回任务结果

如述,功能简单,实现容易,我只是把这种需求通用化了一下,让还没有类似轮子的朋友可以拿去就用。另外还有个基于BackgroundWorker的实现方式,我可能会在下一篇文章分享。

先看一下大致的使用示例:

【C#】分享带等待窗体的任务执行器一枚【C#】分享带等待窗体的任务执行器一枚
//WaitUI就是执行器private void button1_Click(object sender, EventArgs es){  //可检测执行器是否正在执行另一个任务。其实基本不可能出现IsBusy=true,因为执行器工作时,用户做不了其它事  //老实说这个IsBusy要不要公开我还纠结了一下,因为公开了没什么用,但也没什么坏处,因为setter是private的  //Whatever~最后我还是选择公开,可能~因为爱情  //if (WaitUI.IsBusy) { return; }  try  {    //WaitUI.RunXXX方法用于执行任务    //该方法的返回值就是任务的返回值    //任务抛出的异常会通过RunXXX方法抛出    //WaitUI.RunAction(Foo, 33, 66);                   //执行无返回值的方法    int r = WaitUI.RunFunc(Foo, 33, 66);                 //执行有返回值的方法    //object r = WaitUI.RunDelegate(new Func<int, int, int>(Foo), 33, 66);//执行委托    //WaitUI.RunAction(new MyWaitForm(), Foo);//指定自定义等待窗体执行任务,几个RunXXX方法都有可指定自定义窗体的重载    MessageBoxEx.Show("任务完成。" + r);  }  catch (WorkCancelledException)//任务被取消是通过抛出该异常来报告  {    MessageBoxEx.Show("任务已取消!");  }  catch (Exception ex)//任务抛出的异常  {    MessageBoxEx.Show("任务出现异常!" + ex.Message);  }}//耗时任务。因为该方**在后台线程执行,所以方法中不可以有访问控件的代码int Foo(int a, int b){  //可以通过执行器的一系列公开属性和方法间接操作等待窗体的UI元素  WaitUI.CancelControlVisible = true;//设置取消任务的控件的可见性,即是否允许用户取消任务(默认是false:不可见)  WaitUI.BarStyle = ProgressBarStyle.Continuous;//设置滚动条样式(默认是Marquee:循环梭动式)  WaitUI.BarMaximum = 100;   //设置滚动条值上限(默认是100)  WaitUI.BarMinimum = 0;    //设置滚动条值下限(默认是0)  WaitUI.BarStep = 1;      //设置滚动条步进幅度(默认是10)  WaitUI.BarVisible = true;   //设置滚动条是否可见(默认是true:可见)  int i;  for (i = a; i < b; i++)  {    if (WaitUI.UserCancelling)//响应用户的取消请求    {      WaitUI.Cancelled = true;//告诉执行器任务已取消      return 0;    }    //可以抛个异常试试    //if (i == 43) { throw new NotSupportedException("异常测试"); }    //可以随时再次操作等待窗体的各种UI元素    //if (i % 10 == 0) { WaitUI.CancelControlVisible = false; }  //隐藏取消控件    //else if (i % 5 == 0) { WaitUI.CancelControlVisible = true; }//显示取消控件    WaitUI.WorkMessage = "正在XXOO,已完成 " + i + " 下..."; //更新进度描述    WaitUI.BarValue = i;//更新进度值    //WaitUI.BarPerformStep();//步进进度条    Thread.Sleep(100);  }  return i;}

原标题:【C#】分享带等待窗体的任务执行器一枚

关键词:C#

C#
*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。

可能感兴趣文章

我的浏览记录