适用环境:.net 2.0+的Winform项目。
先解释一下我所谓的【带等待窗体的任务执行器】是个什么鬼,就是可以用该类执行任意耗时方法(下文将把被执行的方法称为任务或任务方法),执行期间会显示一个模式等待窗体,让用户知道任务正在得到执行,程序并没有卡死。先看一下效果:
如述,功能简单,实现容易,我只是把这种需求通用化了一下,让还没有类似轮子的朋友可以拿去就用。另外还有个基于BackgroundWorker的实现方式,我可能会在下一篇文章分享。
先看一下大致的使用示例:
adb82fea" class="code_img_closed" src="/Upload/Images/2015041516/0015B68B3C38AA5B.gif" alt="" />logs_code_hide('0579c9cf-3e8a-42e6-a6ec-2fceadb82fea',event)" src="/Upload/Images/2015041516/2B1B950FA3DF188F.gif" alt="" />//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; }使用示例
看完示例,熟悉套路的你可能都已经能洞悉实现细节了,不过作为方案分享文章,我还是照章讲一下使用说明先,后面再掰扯实现说明,先看类图:
int a = 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);
即要先构造好参数数组(哪怕只有1个参数),完了传入数组,最后从数组中取出的元素才是被蹂蹑过的。不能直接传入单个参数变量,那样你是不能通过变量取回改动过的值的,具体原因自己悟
WaitUI.cs包含class WaitUI和3个异常类WaitFormNullException、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<object>(() => 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<object>(() => 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<object>(() => 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<object>(() => 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<object>(() => 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<object>(() => 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<object>(() => 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<object>(() => 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 { //这里不能用waitForm.Hide()关闭等待窗体,因为回调方法仍然是用后台线程执行,不能操作UI waitForm.DialogResult = DialogResult.OK; isCallBackCompleted = true; } } /// <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 WaitFormNullException : ApplicationException { public WaitFormNullException() : base("等待窗体不能为null!") { } } /// <summary> /// 任务正在执行 /// </summary> public class WorkIsBusyException : InvalidOperationException { public WorkIsBusyException() : base("任务正在执行!") { } } /// <summary> /// 任务已被取消 /// </summary> public class WorkCancelledException : ApplicationException { public WorkCancelledException() : base("任务已被取消!") { } } }WaitUI.cs
WaitForm.cs包含interface IWaitForm和class WaitForm,其中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; this.FormClosing += WaitForm_FormClosing; } #region 将【取消】按钮点击、窗体关闭等行为视为触发【取消任务】事件 private void WaitForm_FormClosing(object sender, FormClosingEventArgs e) { if (e.CloseReason == CloseReason.UserClosing) { e.Cancel = true; this.OnUserCancelling(); } } private void btnCancel_Click(object sender, EventArgs e) { this.btnCancel.Enabled = false; 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 #region 用于隐藏等待窗体,调用时二选一即可 //之所以要同实现DialogResult属性和Hide方法,是因为在客户端中需要隐藏窗体时,执行隐藏操作的线程是否UI线程要区别对待, //是UI线程则选用Hide()方法,否则选用DialogResult属性 /// <summary> /// 获取或设置窗体对话框结果 /// </summary> /// <remarks>建议使用Form类的默认实现</remarks> DialogResult DialogResult { get; set; } /// <summary> /// 隐藏等待窗体 /// </summary> /// <remarks>建议使用Form类的默认实现</remarks> void Hide(); #endregion /// <summary> /// 当用户请求取消任务时 /// </summary> /// <remarks>应在用户交互取消控件、关闭窗体时触发该事件</remarks> event EventHandler UserCancelling; } }WaitForm.cs
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); } } }WinFormHelper.cs
可怜的.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); }Delegates.cs
--------------华丽丽的分隔线--------------
下面的内容献给闲的蛋疼的童鞋,又或者你想鄙视、教育我这里不该怎样怎样,那里应该怎样怎样的话,请看完再继续。
using(WaitUI w = new WaitUI()) { w.CancelControlVisible = true; w.RunAction(Foo); }
怎么都不如一句WaitUI.RunAction(Foo)来的简单;②不必改造任务方法。想象一下,实例类的话,任务中想更新等待窗体,是不是得获得执行器实例的引用,或是某个包装了执行器实例的类的实例,怎么获得,自然是通过任务方法的参数传进去,像这样:
int Foo(int a, int b, WaitUI w) { w.WorkMessage = ""; ...
其结果就是必然要改造任务方法,而我的目的一是让用户拿去就能用,结果还要改这改那的我都闲害臊;二是让任务方法既可以套上执行器执行,也可以不带套照常执行,所以WorkMessage那些属性都是写成绿色无公害的,不管有没有等待窗体,都不会抛异常,目的就是即便任务方法中增加了这些语句,也可以在不带套的情况下照常执行
最后真心希望路过大虾对方案不妥之处指点一二,在此谢过。
-文毕-