-------------201504161039更新-------------
-------------20150415原文(已更新)-------------
适用环境:.net 2.0+的Winform项目。
先解释一下我所谓的【带等待窗体的任务执行器】是个什么鬼,就是可以用该类执行任意耗时方法(下文将把被执行的方法称为任务或任务方法),执行期间会显示一个模式等待窗体,让用户知道任务正在得到执行,程序并没有卡死。先看一下效果:
如述,功能简单,实现容易,我只是把这种需求通用化了一下,让还没有类似轮子的朋友可以拿去就用。另外还有个基于BackgroundWorker的实现方式,我可能会在下一篇文章分享。
先看一下大致的使用示例:
//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方法都有可指定自定义窗体的重载
MessageBox.Show("任务完成。" + r);
}
catch (WorkCancelledException)//任务被取消是通过抛出该异常来报告
{
MessageBox.Show("任务已取消!");
}
catch (Exception ex)//任务抛出的异常
{
MessageBox.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(50);
}
return i;
}
看完示例,熟悉套路的你可能都已经能洞悉实现细节了,不过作为方案分享文章,我还是照章讲一下使用说明先,后面再掰扯设计说明,先看类图:
int a = WaitUI.RunFunc(Foo,33);
int b = Foo(33);
//正确
object[] prms = { a, b };
WaitUI.RunDelegate(new Action(Foo), prms);
a = prms[0];
b = prms[1];
//错误
WaitUI.RunDelegate(new Action(Foo), a, b);
WaitUI.cs包含class WaitUI和2个异常类WorkIsBusyException、WorkCancelledException
using System;
using System.Reflection;
using System.Windows.Forms;
namespace AhDung.WinForm
{
/// <summary>
/// 执行任务并显示等候窗体
/// </summary>
public static class WaitUI
{
static IWaitForm waitForm; //等待窗体
static object result; //任务返回结果
static Exception exception;//任务执行异常
static object[] parmsInput; //调用者传入的参数
static ParameterInfo[] parmsMethod;//任务所需的参数
static bool isCallBackCompleted; //指示回调方法是否已执行完毕
/// <summary>
/// 指示用户是否已请求取消任务
/// </summary>
public static bool UserCancelling
{
get;
private set;
}
/// <summary>
/// 指示任务是否已取消
/// </summary>
public static bool Cancelled
{
private get;
set;
}
/// <summary>
/// 指示任务是否正在执行中
/// </summary>
public static bool IsBusy
{
get;
private set;
}
#region 一组操作等候窗体UI的属性/方法
/// <summary>
/// 获取或设置进度描述
/// </summary>
public static string WorkMessage
{
get
{
if (waitForm.InvokeRequired)
{
return waitForm.Invoke(new Func<string>(() => waitForm.WorkMessage)) as string;
}
return waitForm.WorkMessage;
}
set
{
if (waitForm == null) { return; }
if (waitForm.InvokeRequired)
{
waitForm.BeginInvoke(new Action(() => waitForm.WorkMessage = value));
return;
}
waitForm.WorkMessage = value;
}
}
/// <summary>
/// 获取或设置进度条可见性
/// </summary>
public static bool BarVisible
{
get
{
if (waitForm.InvokeRequired)
{
return Convert.ToBoolean(waitForm.Invoke(new Func<bool>(() => waitForm.BarVisible)));
}
return waitForm.BarVisible;
}
set
{
if (waitForm == null) { return; }
if (waitForm.InvokeRequired)
{
waitForm.BeginInvoke(new Action(() => waitForm.BarVisible = value));
return;
}
waitForm.BarVisible = value;
}
}
/// <summary>
/// 获取或设置进度条动画样式
/// </summary>
public static ProgressBarStyle BarStyle
{
get
{
if (waitForm.InvokeRequired)
{
return (ProgressBarStyle)(waitForm.Invoke(new Func<ProgressBarStyle>(() => waitForm.BarStyle)));
}
return waitForm.BarStyle;
}
set
{
if (waitForm == null) { return; }
if (waitForm.InvokeRequired)
{
waitForm.BeginInvoke(new Action(() => waitForm.BarStyle = value));
return;
}
waitForm.BarStyle = value;
}
}
/// <summary>
/// 获取或设置进度值
/// </summary>
public static int BarValue
{
get
{
if (waitForm.InvokeRequired)
{
return Convert.ToInt32(waitForm.Invoke(new Func<int>(() => waitForm.BarValue)));
}
return waitForm.BarValue;
}
set
{
if (waitForm == null) { return; }
if (waitForm.InvokeRequired)
{
waitForm.BeginInvoke(new Action(() => waitForm.BarValue = value));
return;
}
waitForm.BarValue = value;
}
}
/// <summary>
/// 获取或设置进度条步进值
/// </summary>
public static int BarStep
{
get
{
if (waitForm.InvokeRequired)
{
return Convert.ToInt32(waitForm.Invoke(new Func<int>(() => waitForm.BarStep)));
}
return waitForm.BarStep;
}
set
{
if (waitForm == null) { return; }
if (waitForm.InvokeRequired)
{
waitForm.BeginInvoke(new Action(() => waitForm.BarStep = value));
return;
}
waitForm.BarStep = value;
}
}
/// <summary>
/// 使进度条步进
/// </summary>
public static void BarPerformStep()
{
if (waitForm == null) { return; }
if (waitForm.InvokeRequired)
{
waitForm.BeginInvoke(new Action(() => waitForm.BarPerformStep()));
return;
}
waitForm.BarPerformStep();
}
/// <summary>
/// 获取或设置进度条上限值
/// </summary>
public static int BarMaximum
{
get
{
if (waitForm.InvokeRequired)
{
return Convert.ToInt32(waitForm.Invoke(new Func<int>(() => waitForm.BarMaximum)));
}
return waitForm.BarMaximum;
}
set
{
if (waitForm == null) { return; }
if (waitForm.InvokeRequired)
{
waitForm.BeginInvoke(new Action(() => waitForm.BarMaximum = value));
return;
}
waitForm.BarMaximum = value;
}
}
/// <summary>
/// 获取或设置进度条下限值
/// </summary>
public static int BarMinimum
{
get
{
if (waitForm.InvokeRequired)
{
return Convert.ToInt32(waitForm.Invoke(new Func<int>(() => waitForm.BarMinimum)));
}
return waitForm.BarMinimum;
}
set
{
if (waitForm == null) { return; }
if (waitForm.InvokeRequired)
{
waitForm.BeginInvoke(new Action(() => waitForm.BarMinimum = value));
return;
}
waitForm.BarMinimum = value;
}
}
/// <summary>
/// 获取或设置取消任务的控件的可见性
/// </summary>
public static bool CancelControlVisible
{
get
{
if (waitForm.InvokeRequired)
{
return Convert.ToBoolean(waitForm.Invoke(new Func<bool>(() => waitForm.CancelControlVisible)));
}
return waitForm.CancelControlVisible;
}
set
{
if (waitForm == null) { return; }
if (waitForm.InvokeRequired)
{
waitForm.BeginInvoke(new Action(() => waitForm.CancelControlVisible = value));
return;
}
waitForm.CancelControlVisible = value;
}
}
#endregion
#region 公共方法:无返回值+默认窗体
/// <summary>
/// 执行方法并显示默认等候窗体
/// </summary>
public static void RunAction(Action method)
{
RunDelegate(method);
}
/// <summary>
/// 执行方法并显示默认等候窗体
/// </summary>
public static void RunAction<T>(Action<T> method, T arg)
{
RunDelegate(method, arg);
}
/// <summary>
/// 执行方法并显示默认等候窗体
/// </summary>
public static void RunAction<T1, T2>(Action<T1, T2> method, T1 arg1, T2 arg2)
{
RunDelegate(method, arg1, arg2);
}
/// <summary>
/// 执行方法并显示默认等候窗体
/// </summary>
public static void RunAction<T1, T2, T3>(Action<T1, T2, T3> method, T1 arg1, T2 arg2, T3 arg3)
{
RunDelegate(method, arg1, arg2, arg3);
}
/// <summary>
/// 执行方法并显示默认等候窗体
/// </summary>
public static void RunAction<T1, T2, T3, T4>(Action<T1, T2, T3, T4> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
{
RunDelegate(method, arg1, arg2, arg3, arg4);
}
/// <summary>
/// 执行方法并显示默认等候窗体
/// </summary>
public static void RunAction<T1, T2, T3, T4, T5>(Action<T1, T2, T3, T4, T5> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
{
RunDelegate(method, arg1, arg2, arg3, arg4, arg5);
}
/// <summary>
/// 执行方法并显示默认等候窗体
/// </summary>
public static void RunAction<T1, T2, T3, T4, T5, T6>(Action<T1, T2, T3, T4, T5, T6> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6)
{
RunDelegate(method, arg1, arg2, arg3, arg4, arg5, arg6);
}
/// <summary>
/// 执行方法并显示默认等候窗体
/// </summary>
public static void RunAction<T1, T2, T3, T4, T5, T6, T7>(Action<T1, T2, T3, T4, T5, T6, T7> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7)
{
RunDelegate(method, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
}
/// <summary>
/// 执行方法并显示默认等候窗体
/// </summary>
public static void RunAction<T1, T2, T3, T4, T5, T6, T7, T8>(Action<T1, T2, T3, T4, T5, T6, T7, T8> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8)
{
RunDelegate(method, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
}
#endregion
#region 公共方法:无返回值+自定义窗体
/// <summary>
/// 执行方法并显示自定义等候窗体
/// </summary>
public static void RunAction(IWaitForm fmWait, Action method)
{
RunDelegate(fmWait, method);
}
/// <summary>
/// 执行方法并显示自定义等候窗体
/// </summary>
public static void RunAction<T>(IWaitForm fmWait, Action<T> method, T arg)
{
RunDelegate(fmWait, method, arg);
}
/// <summary>
/// 执行方法并显示自定义等候窗体
/// </summary>
public static void RunAction<T1, T2>(IWaitForm fmWait, Action<T1, T2> method, T1 arg1, T2 arg2)
{
RunDelegate(fmWait, method, arg1, arg2);
}
/// <summary>
/// 执行方法并显示自定义等候窗体
/// </summary>
public static void RunAction<T1, T2, T3>(IWaitForm fmWait, Action<T1, T2, T3> method, T1 arg1, T2 arg2, T3 arg3)
{
RunDelegate(fmWait, method, arg1, arg2, arg3);
}
/// <summary>
/// 执行方法并显示自定义等候窗体
/// </summary>
public static void RunAction<T1, T2, T3, T4>(IWaitForm fmWait, Action<T1, T2, T3, T4> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
{
RunDelegate(fmWait, method, arg1, arg2, arg3, arg4);
}
/// <summary>
/// 执行方法并显示自定义等候窗体
/// </summary>
public static void RunAction<T1, T2, T3, T4, T5>(IWaitForm fmWait, Action<T1, T2, T3, T4, T5> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
{
RunDelegate(fmWait, method, arg1, arg2, arg3, arg4, arg5);
}
/// <summary>
/// 执行方法并显示自定义等候窗体
/// </summary>
public static void RunAction<T1, T2, T3, T4, T5, T6>(IWaitForm fmWait, Action<T1, T2, T3, T4, T5, T6> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6)
{
RunDelegate(fmWait, method, arg1, arg2, arg3, arg4, arg5, arg6);
}
/// <summary>
/// 执行方法并显示自定义等候窗体
/// </summary>
public static void RunAction<T1, T2, T3, T4, T5, T6, T7>(IWaitForm fmWait, Action<T1, T2, T3, T4, T5, T6, T7> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7)
{
RunDelegate(fmWait, method, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
}
/// <summary>
/// 执行方法并显示自定义等候窗体
/// </summary>
public static void RunAction<T1, T2, T3, T4, T5, T6, T7, T8>(IWaitForm fmWait, Action<T1, T2, T3, T4, T5, T6, T7, T8> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8)
{
RunDelegate(fmWait, method, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
}
#endregion
#region 公共方法:有返回值+默认窗体
/// <summary>
/// 执行方法并显示默认等候窗体
/// </summary>
public static TResult RunFunc<TResult>(Func<TResult> method)
{
return (TResult)RunDelegate(method);
}
/// <summary>
/// 执行方法并显示默认等候窗体
/// </summary>
public static TResult RunFunc<T, TResult>(Func<T, TResult> method, T arg)
{
return (TResult)RunDelegate(method, arg);
}
/// <summary>
/// 执行方法并显示默认等候窗体
/// </summary>
public static TResult RunFunc<T1, T2, TResult>(Func<T1, T2, TResult> method, T1 arg1, T2 arg2)
{
return (TResult)RunDelegate(method, arg1, arg2);
}
/// <summary>
/// 执行方法并显示默认等候窗体
/// </summary>
public static TResult RunFunc<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> method, T1 arg1, T2 arg2, T3 arg3)
{
return (TResult)RunDelegate(method, arg1, arg2, arg3);
}
/// <summary>
/// 执行方法并显示默认等候窗体
/// </summary>
public static TResult RunFunc<T1, T2, T3, T4, TResult>(Func<T1, T2, T3, T4, TResult> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
{
return (TResult)RunDelegate(method, arg1, arg2, arg3, arg4);
}
/// <summary>
/// 执行方法并显示默认等候窗体
/// </summary>
public static TResult RunFunc<T1, T2, T3, T4, T5, TResult>(Func<T1, T2, T3, T4, T5, TResult> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
{
return (TResult)RunDelegate(method, arg1, arg2, arg3, arg4, arg5);
}
/// <summary>
/// 执行方法并显示默认等候窗体
/// </summary>
public static TResult RunFunc<T1, T2, T3, T4, T5, T6, TResult>(Func<T1, T2, T3, T4, T5, T6, TResult> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6)
{
return (TResult)RunDelegate(method, arg1, arg2, arg3, arg4, arg5, arg6);
}
/// <summary>
/// 执行方法并显示默认等候窗体
/// </summary>
public static TResult RunFunc<T1, T2, T3, T4, T5, T6, T7, TResult>(Func<T1, T2, T3, T4, T5, T6, T7, TResult> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7)
{
return (TResult)RunDelegate(method, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
}
/// <summary>
/// 执行方法并显示默认等候窗体
/// </summary>
public static TResult RunFunc<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8)
{
return (TResult)RunDelegate(method, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
}
#endregion
#region 公共方法:有返回值+自定义窗体
/// <summary>
/// 执行方法并显示自定义等候窗体
/// </summary>
public static TResult RunFunc<TResult>(IWaitForm fmWait, Func<TResult> method)
{
return (TResult)RunDelegate(fmWait, method);
}
/// <summary>
/// 执行方法并显示自定义等候窗体
/// </summary>
public static TResult RunFunc<T, TResult>(IWaitForm fmWait, Func<T, TResult> method, T arg)
{
return (TResult)RunDelegate(fmWait, method, arg);
}
/// <summary>
/// 执行方法并显示自定义等候窗体
/// </summary>
public static TResult RunFunc<T1, T2, TResult>(IWaitForm fmWait, Func<T1, T2, TResult> method, T1 arg1, T2 arg2)
{
return (TResult)RunDelegate(fmWait, method, arg1, arg2);
}
/// <summary>
/// 执行方法并显示自定义等候窗体
/// </summary>
public static TResult RunFunc<T1, T2, T3, TResult>(IWaitForm fmWait, Func<T1, T2, T3, TResult> method, T1 arg1, T2 arg2, T3 arg3)
{
return (TResult)RunDelegate(fmWait, method, arg1, arg2, arg3);
}
/// <summary>
/// 执行方法并显示自定义等候窗体
/// </summary>
public static TResult RunFunc<T1, T2, T3, T4, TResult>(IWaitForm fmWait, Func<T1, T2, T3, T4, TResult> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
{
return (TResult)RunDelegate(fmWait, method, arg1, arg2, arg3, arg4);
}
/// <summary>
/// 执行方法并显示自定义等候窗体
/// </summary>
public static TResult RunFunc<T1, T2, T3, T4, T5, TResult>(IWaitForm fmWait, Func<T1, T2, T3, T4, T5, TResult> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
{
return (TResult)RunDelegate(fmWait, method, arg1, arg2, arg3, arg4, arg5);
}
/// <summary>
/// 执行方法并显示自定义等候窗体
/// </summary>
public static TResult RunFunc<T1, T2, T3, T4, T5, T6, TResult>(IWaitForm fmWait, Func<T1, T2, T3, T4, T5, T6, TResult> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6)
{
return (TResult)RunDelegate(fmWait, method, arg1, arg2, arg3, arg4, arg5, arg6);
}
/// <summary>
/// 执行方法并显示自定义等候窗体
/// </summary>
public static TResult RunFunc<T1, T2, T3, T4, T5, T6, T7, TResult>(IWaitForm fmWait, Func<T1, T2, T3, T4, T5, T6, T7, TResult> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7)
{
return (TResult)RunDelegate(fmWait, method, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
}
/// <summary>
/// 执行方法并显示自定义等候窗体
/// </summary>
public static TResult RunFunc<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(IWaitForm fmWait, Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult> method, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8)
{
return (TResult)RunDelegate(fmWait, method, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
}
#endregion
/// <summary>
/// 执行委托并显示默认等候窗体
/// </summary>
public static object RunDelegate(Delegate del, params object[] args)
{
return RunDelegate(new WaitForm(), del, args);
}
/// <summary>
/// 执行委托并显示自定义等候窗体
/// </summary>
public static object RunDelegate(IWaitForm fmWait, Delegate del, params object[] args)
{
if (IsBusy) { throw new WorkIsBusyException(); }
if (fmWait == null) { throw new WaitFormNullException(); }
if (del == null || del.GetInvocationList().Length != 1) { throw new ApplicationException("委托不能为空,且只能绑定1个方法!"); }
if (args == null) { throw new ArgumentNullException("args"); }
MethodInfo beginInvoke = del.GetType().GetMethod("BeginInvoke");
object[] parmsBeginInvoke = new object[beginInvoke.GetParameters().Length];
if (args.Length > parmsBeginInvoke.Length - 2)
{
throw new ArgumentException("提供的参数超过了方法所需的参数!");
}
parmsMethod = del.Method.GetParameters();//假定GetParameters总是返回按参数Position排序的数组,如果将来有问题,要查验这个假设
parmsInput = args;
try
{
//赋值BeginInvoke参数
parmsInput.CopyTo(parmsBeginInvoke, 0); //塞入传入的参数
for (int i = parmsInput.Length; i < parmsMethod.Length; i++) //对未传入的参数赋予默认值
{
ParameterInfo p = parmsMethod[i];
object pVal;
if ((pVal = p.DefaultValue) == DBNull.Value) //若参数不具有默认值则抛异常
{ throw new ArgumentException(string.Format("方法所需的参数{0}没有定义默认值,必须传入!", p.Name)); }
parmsBeginInvoke[i] = pVal;
}
parmsBeginInvoke[parmsBeginInvoke.Length - 2] = new AsyncCallback(Callback);//倒数第2个参数
parmsBeginInvoke[parmsBeginInvoke.Length - 1] = del; //倒数第1个参数
//重置状态
IsBusy = true;
Cancelled = false;
exception = null;
isCallBackCompleted = false;
waitForm = fmWait;
fmWait.UserCancelling += WaitForm_UserCancelling;//注册用户取消任务事件
beginInvoke.Invoke(del, parmsBeginInvoke);
if (!isCallBackCompleted)//这里要判断一下,极端情况下有可能还没等ShowDialog,回调就执行完了
{
fmWait.ShowDialog(); //务必确保ShowDialog不会抛异常
}
//返回
if (Cancelled) { throw new WorkCancelledException(); }
if (exception != null) { throw exception; }
return result;
}
finally
{
Release();
UserCancelling = false;
IsBusy = false;
}
}
/// <summary>
/// 回调方法
/// </summary>
private static void Callback(IAsyncResult ar)
{
try
{
if (Cancelled) { return; } //若任务取消就不必EndInvoke了
MethodInfo endInvoke = ar.AsyncState.GetType().GetMethod("EndInvoke");
object[] parmsEndInvoke = new object[endInvoke.GetParameters().Length];
if (parmsEndInvoke.Length != 1)//若方法存在ref或out参数,赋值给endInvoke参数
{
int i = 0;
foreach (ParameterInfo p in parmsMethod)
{
if (p.ParameterType.IsByRef) { parmsEndInvoke[i++] = parmsInput[p.Position]; }
}
}
parmsEndInvoke[parmsEndInvoke.Length - 1] = ar;
result = endInvoke.Invoke(ar.AsyncState, parmsEndInvoke);
if (parmsEndInvoke.Length != 1)//从endInvoke参数取出值返给输入参数
{
int i = 0;
foreach (ParameterInfo p in parmsMethod)
{
if (p.ParameterType.IsByRef) { parmsInput[p.Position] = parmsEndInvoke[i++]; }
}
}
}
catch (TargetInvocationException ex)
{
exception = ex.InnerException;
}
catch (Exception ex)
{
exception = ex;
}
finally
{
HideWaitForm();
isCallBackCompleted = true;
}
}
/// <summary>
/// 隐藏等待窗体
/// </summary>
/// <remarks>因为该方法会在回调中调用,所以要做跨线程处理</remarks>
static void HideWaitForm()
{
if (waitForm == null) { return; }
if (waitForm.InvokeRequired)
{
waitForm.BeginInvoke(new Action(() => waitForm.Hide()));
return;
}
waitForm.Hide();
}
/// <summary>
/// 用户请求取消任务时
/// </summary>
private static void WaitForm_UserCancelling(object sender, EventArgs e)
{
UserCancelling = true;
}
/// <summary>
/// 释放资源
/// </summary>
private static void Release()
{
parmsInput = null;//这里不会影响调用者传入的object[]实例,因为不是ref进来的
parmsMethod = null;
IDisposable disp;
if ((disp = waitForm as IDisposable) != null) { disp.Dispose(); }
}
}
/// <summary>
/// 任务正在执行
/// </summary>
public class WorkIsBusyException : InvalidOperationException
{
public WorkIsBusyException() : base("任务正在执行!") { }
}
/// <summary>
/// 任务已被取消
/// </summary>
public class WorkCancelledException : ApplicationException
{
public WorkCancelledException() : base("任务已被取消!") { }
}
}
WaitForm.cs包含interface IWaitForm、class WaitForm和异常类WaitFormNullException,其中WaitForm为了屏蔽关闭按钮,使用了WinFormHelper.cs
using System;
using System.Windows.Forms;
namespace AhDung.WinForm
{
/// <summary>
/// 等待窗体
/// </summary>
///<remarks>IWaitForm的默认实现</remarks>
public class WaitForm : Form, IWaitForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private readonly System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.lbMsg = new System.Windows.Forms.Label();
this.bar = new System.Windows.Forms.ProgressBar();
this.btnCancel = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// lbMsg
//
this.lbMsg.Location = new System.Drawing.Point(10, 20);
this.lbMsg.Name = "lbMsg";
this.lbMsg.Size = new System.Drawing.Size(386, 55);
this.lbMsg.TabIndex = 0;
this.lbMsg.Text = "正在处理,请稍候...";
//
// bar
//
this.bar.Location = new System.Drawing.Point(12, 78);
this.bar.Name = "bar";
this.bar.Step = 1;
this.bar.Size = new System.Drawing.Size(384, 16);
this.bar.Style = System.Windows.Forms.ProgressBarStyle.Marquee;
this.bar.TabIndex = 1;
//
// btnCancel
//
this.btnCancel.Location = new System.Drawing.Point(321, 109);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(75, 23);
this.btnCancel.TabIndex = 2;
this.btnCancel.Text = "取消";
this.btnCancel.UseVisualStyleBackColor = true;
this.btnCancel.Visible = false;
//
// FmWaitForDesign
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(408, 155);
this.Controls.Add(this.btnCancel);
this.Controls.Add(this.bar);
this.Controls.Add(this.lbMsg);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.Name = "FmWaitForDesign";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "请稍候...";
this.ResumeLayout(false);
}
#endregion
System.Windows.Forms.Label lbMsg;
System.Windows.Forms.Button btnCancel;
System.Windows.Forms.ProgressBar bar;
public WaitForm()
{
InitializeComponent();
btnCancel.Click += btnCancel_Click;//注册取消按钮单击事件
}
#region 将【取消】按钮点击、窗体关闭等行为视为触发【取消任务】事件
protected override void OnFormClosing(FormClosingEventArgs e)
{
//阻止用户关闭窗体并触发UserCancelling事件
//加Visible是因为调用Hide()也会触发该事件,为了避免再次OnUserCancelling为之
if (e.CloseReason == CloseReason.UserClosing && this.Visible)
{
e.Cancel = true;
this.OnUserCancelling();
}
base.OnFormClosing(e);
}
private void btnCancel_Click(object sender, EventArgs e)
{
this.OnUserCancelling();
}
protected virtual void OnUserCancelling()
{
if (UserCancelling != null) { UserCancelling(this, EventArgs.Empty); }
}
//屏蔽窗体关闭按钮
protected override void OnVisibleChanged(EventArgs e)
{
base.OnVisibleChanged(e);
if (this.Visible) { AhDung.WinForm.WinFormHelper.DisableCloseButton(this); }
}
#endregion
#region 实现接口
public string WorkMessage
{
get { return lbMsg.Text; }
set { lbMsg.Text = value; }
}
public bool BarVisible
{
get { return bar.Visible; }
set { bar.Visible = value; }
}
public ProgressBarStyle BarStyle
{
get { return bar.Style; }
set { bar.Style = value; }
}
public int BarValue
{
get { return bar.Value; }
set { bar.Value = value; }
}
public int BarStep
{
get { return bar.Step; }
set { bar.Step = value; }
}
public void BarPerformStep()
{
bar.PerformStep();
}
public bool CancelControlVisible
{
get { return btnCancel.Visible; }
set { btnCancel.Visible = value; }
}
public int BarMaximum
{
get { return bar.Maximum; }
set { bar.Maximum = value; }
}
public int BarMinimum
{
get { return bar.Minimum; }
set { bar.Minimum = value; }
}
public event EventHandler UserCancelling;
#endregion
}
/// <summary>
/// 等待窗体规范
/// </summary>
public interface IWaitForm
{
#region 用于操作等待窗体UI表现的属性和方法,实现时不用操心线程问题,让客户端(任务执行器)去操心
/// <summary>
/// 获取或设置进度描述
/// </summary>
/// <remarks>建议默认值为“请稍候...”之类的字眼</remarks>
string WorkMessage { get; set; }
/// <summary>
/// 获取或设置进度条的可见性
/// </summary>
/// <remarks>建议默认值为true</remarks>
bool BarVisible { get; set; }
/// <summary>
/// 获取或设置进度条的动画样式
/// </summary>
/// <remarks>建议默认值为Marquee</remarks>
ProgressBarStyle BarStyle { get; set; }
/// <summary>
/// 获取或设置进度条的值
/// </summary>
/// <remarks>建议默认值为0</remarks>
int BarValue { get; set; }
/// <summary>
/// 获取或设置进度条的步进幅度
/// </summary>
int BarStep { get; set; }
/// <summary>
/// 使进度条步进
/// </summary>
void BarPerformStep();
/// <summary>
/// 获取或设置取消任务的控件的可见性
/// </summary>
/// <remarks>建议默认值为false</remarks>
bool CancelControlVisible { get; set; }
/// <summary>
/// 获取或设置进度条的值上限
/// </summary>
/// <remarks>建议默认值为100</remarks>
int BarMaximum { get; set; }
/// <summary>
/// 获取或设置进度条的值下限
/// </summary>
/// <remarks>建议默认值为0</remarks>
int BarMinimum { get; set; }
#endregion
/// <summary>
/// 显示模式等待窗体
/// </summary>
/// <remarks>建议使用Form类的默认实现</remarks>
DialogResult ShowDialog();
#region Invoke相关,供客户端在跨线程操作窗体UI
/// <summary>
/// 指示是否需要使用Invoke操作窗体控件
/// </summary>
/// <remarks>建议使用Form类的默认实现</remarks>
bool InvokeRequired { get; }
/// <summary>
/// 窗体Invoke方法
/// </summary>
/// <remarks>建议使用Form类的默认实现</remarks>
object Invoke(Delegate method);
/// <summary>
/// 窗体BeginInvoke方法
/// </summary>
/// <remarks>建议使用Form类的默认实现</remarks>
IAsyncResult BeginInvoke(Delegate method);
#endregion
/// <summary>
/// 隐藏等待窗体
/// </summary>
/// <remarks>建议使用Form类的默认实现</remarks>
void Hide();
/// <summary>
/// 当用户请求取消任务时
/// </summary>
/// <remarks>应在用户交互取消控件、关闭窗体时触发该事件</remarks>
event EventHandler UserCancelling;
}
/// <summary>
/// 等候窗体为空
/// </summary>
public class WaitFormNullException : ApplicationException
{
public WaitFormNullException() : base("等待窗体不能为null!") { }
}
}
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace AhDung.WinForm
{
public static class WinFormHelper
{
[DllImport("User32.dll ")]
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("User32.dll ")]
private static extern int RemoveMenu(IntPtr hMenu, int nPosition, int wFlags);
const int MF_REMOVE = 0x1000;
//const int SC_RESTORE = 0xF120; //还原
//const int SC_MOVE = 0xF010; //移动
//const int SC_SIZE = 0xF000; //大小
//const int SC_MINIMIZE = 0xF020; //最小化
//const int SC_MAXIMIZE = 0xF030; //最大化
const int SC_CLOSE = 0xF060; //关闭
/// <summary>
/// 屏蔽窗体关闭功能
/// </summary>
public static void DisableCloseButton(IWin32Window form)
{
IntPtr hMenu = GetSystemMenu(form.Handle, false);
RemoveMenu(hMenu, SC_CLOSE, MF_REMOVE);
}
}
}
可怜的.net 2.0~3.5没有足够的内置委托,所以你可能还需要Delegates.cs
namespace System
{
//无返回委托
public delegate void Action();
//public delegate void Action<in T>(T arg);//这个2.0是有的
public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);
public delegate void Action<in T1, in T2, in T3>(T1 arg1, T2 arg2, T3 arg3);
public delegate void Action<in T1, in T2, in T3, in T4>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
public delegate void Action<in T1, in T2, in T3, in T4, in T5>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6);
public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);
public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8);
//public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9);
//public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10);
//public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11);
//public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12);
//public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13);
//public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14);
//public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15);
//public delegate void Action<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16);
//有返回委托
public delegate TResult Func<out TResult>();
public delegate TResult Func<in T, out TResult>(T arg);
public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
public delegate TResult Func<in T1, in T2, in T3, out TResult>(T1 arg1, T2 arg2, T3 arg3);
public delegate TResult Func<in T1, in T2, in T3, in T4, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6);
public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);
public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8);
//public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9);
//public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10);
//public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11);
//public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12);
//public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13);
//public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14);
//public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15);
//public delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16);
}
--------------华丽丽的分隔线--------------
下面的内容献给闲的蛋疼的童鞋,又或者你想鄙视、教育我这里不该怎样怎样,那里应该怎样怎样的话,请看完再继续。
using(WaitUI w = new WaitUI())
{
w.CancelControlVisible = true;
w.RunAction(Foo);
}
最后真心希望路过大虾对方案不妥之处指点一二,在此谢过。
-文毕-