Beispiel #1
0
        /// <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) { }
                }
            });
        }