/// <summary> /// 执行委托并显示自定义等候窗体 /// </summary> public static object RunDelegate(IWaitForm fmWait, Delegate del, params object[] args) { //利用AutoResetEvent.WaitOne的原子性,防止重入 if (!_areForWhole.WaitOne(0)) { throw new WorkIsBusyException(); } _isRunning = true; try { if (fmWait == null) { throw new ArgumentNullException("fmWait"); } if (del == null || del.GetInvocationList().Length != 1) { throw new ApplicationException("委托不能为空,且只能绑定1个方法!"); } if (args == null) { throw new ArgumentNullException("args"); } Reset(); _waitForm = fmWait;//需在开始异步任务前赋值,因为异步中可能用到 //更新上下文为UI线程上下文,因为如果在Main中Run,先前拿到的上下文也许时null, //会导致在异步完成时用Post关闭窗体抛异常 _waitForm.Shown += (S, E) => _syncContext = SynchronizationContext.Current; StartAsync(del, args); Thread.Sleep(50); //给异步任务一点时间,如果在此时间内完成,就不弹窗 if (!_isCompleted) { //这里有可能出现异步先把wf关了的情况,所以要吃掉这种异常 try { _waitForm.ShowDialog(); } catch (ObjectDisposedException) { } } //返回 if (Cancelled) { throw new WorkCancelledException(); } if (_exception != null) { throw _exception; } return(_result); } finally { Release(); _areForWhole.Set(); _isRunning = false; } }
/// <summary> /// 开始执行后台操作 /// </summary> /// <param name="argument">要在DoWork事件处理程序中使用的参数</param> /// <remarks>通过可选参数可以同时覆盖基类无参RunWorkerAsync,一石二鸟</remarks> public new void RunWorkerAsync(object argument = null) { Form f; activeForm = (f = Form.ActiveForm) != null && f.IsMdiContainer ? f.ActiveMdiChild : f;//记录当时的活动窗体 waitForm.CancelControlVisible = this.WorkerSupportsCancellation; formClosed = false; base.RunWorkerAsync(argument); //这里要判断一下,极端情况下有可能还没等ShowDialog,窗体就已经被关闭了 if (!formClosed) { waitForm.ShowDialog(); } }
/// <summary> /// 开始执行后台操作 /// </summary> /// <param name="argument">要在DoWork事件处理程序中使用的参数</param> /// <remarks>通过可选参数可以同时覆盖基类无参RunWorkerAsync</remarks> public new void RunWorkerAsync(object argument = null) { _waitForm.CancelControlVisible = this.WorkerSupportsCancellation; _waitForm.CancelPending = false;//考虑该方法是可能重复进入的 base.RunWorkerAsync(argument); //给异步任务一点时间,如果在此时间内完成,就不弹窗。 //不能用Sleep,因为异步任务完成是通过Post改IsBusy, //Sleep会把Post也卡住,完了还是先走if,失去意义 DelayRun(50, () => { if (IsBusy) { //这里有可能出现先把wf关了的情况,所以要吃掉这种异常 try { _waitForm.ShowDialog(); } catch (ObjectDisposedException) { } } }); }