耗时异步操作组件

 一.引子

   耗时操作时,我们常常会提供用户一个等待界面,来提醒用户操作还在进行中,并没有结束。方法往往有2种,一种就是同步处理,在操作完成前要一直等待,这样有造成系统假死的可能;另外一种方法就是异步处理,我下面说到的方法就是采用异步处理,并集成到组件中,暴露出启动,取消,完成3个事件给用户,增加友好度。可以在处理过程中取消操作,也可以先去处理其他的任务,等到操作的完成。

二.效果

  

 

三.主要思路

 public virtual void BeginAsyncOperation(object taskId)
        {
            //根据任务号创建跟踪异步操作的生存期对象
            AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(taskId);

           
            //多线程将访问任务字典,所以要锁定任务字典
            lock (_userTaskList.SyncRoot)
            {
                if (_userTaskList.Contains(taskId))//如果已经包含了该任务,则抛出异常
                {
                    throw new ArgumentException("参数任务号ID必须唯一!","参数出错");
                }
                _taskId = taskId;
                //将任务ID与跟踪异步操作对象关联!!!
                _userTaskList[taskId] = asyncOp;
            }
         
            //开始真正的异步操作
            WorkerEventHandler workerDelegate = new WorkerEventHandler(OnCalculateWorker);
            workerDelegate.BeginInvoke(asyncOp, null, null);
           
        }

上面是启动的代码,从中我们不难看出asyncOp被作为了参数在OnCalculateWorker方法中来具体实现异步的操作。

而OnCalculateWorker的代码如下:

protected virtual void OnCalculateWorker(AsyncOperation asyncOp)
        {
            if (!TaskCanceled(asyncOp.UserSuppliedState))
            {
                Exception e = null;
                try
                {

                    if (CalculateWorker != null)
                    {
                        WorkerProgressEventArgs e1 = new WorkerProgressEventArgs(asyncOp, 0);
                        CalculateWorker(this,e1);
                    }
                }
                catch (Exception ex)
                {
                    e = ex;
                }
                //处理结束后的操作
                this.CompletionMethod(e,TaskCanceled(asyncOp.UserSuppliedState),asyncOp);
            }
        }

其中TaskCanceled是判断是否被取消的方法,CalculateWorker是被暴露的耗时操作的事件。我们只要在需要处理复杂操作时建立一个该组件的实例,并在CalculateWorker事件中添加复杂处理的代码就可以完成复杂操作。CompletionMethod方法处理在结束操作时的一些处理。下面时它的代码:

  private void CompletionMethod(Exception exception, bool canceled, AsyncOperation asyncOp)
        {
            //如果没有取消,任务将在结束后依据标识从集合中移除当前的异步操作对象
            if (!canceled)
            {
                //先锁定任务字典,然后从任务字典中移除该任务
                lock (_userTaskList.SyncRoot)
                {
                    _userTaskList.Remove(asyncOp.UserSuppliedState);
                }
                //在任务结束后,跟踪异步对象要结束生存期
                //结束异步调用的生存期(触发OnCompletedDelegate),这个时候会发生回调操作
                asyncOp.PostOperationCompleted(onCompletedDelegate, new AsyncCompletedEventArgs(null, false, null));
            }
            else
            {
                //在任务结束后,跟踪异步对象要结束生存期
                //结束异步调用的生存期(触发OnCompletedDelegate),这个时候会发生回调操作
                asyncOp.PostOperationCompleted(onCompletedDelegate,null);
            }
        }

其中,onCompletedDelegate是一个委托,它的关联方法是

private void CalculateCompleted(object operationState)
        {
            AsyncCompletedEventArgs e = operationState as AsyncCompletedEventArgs;
            OnCalculateCompleted(e);
        }
其中,OnCalculateCompleted的代码如下:

 protected virtual void OnCalculateCompleted(AsyncCompletedEventArgs e)
        {
            if (e != null)
            {
                if (AsyncEventCompleted != null && !e.Cancelled)
                    AsyncEventCompleted(this, e);
            }
            if (_isCanceled)
                _isCanceled = false;
        }

从上可见,引发了AsyncEventCompleted事件。该事件也正是我前面提到的异步完成的事件。

下面是调用该组件的代码:

            this.Text = "begin!";            
            Guid guid = Guid.NewGuid();
            _guid = guid;
            this.jcsAsyncComponet1.BeginAsyncOperation(guid);

            this._frm = new FrmWait();
            _frm.Owner = this;
          
            _frm.StartPosition = FormStartPosition.CenterScreen;

            _frm.CloseEvent += new EventHandler(_frm_CloseEvent);
            _frm.Show();

其中_frm就是我们在前面看到的图片对应的窗体。该窗体中用到了我前面提到的等待控件JcsWaitControl,这个不重要,我们放一个ProcessBar也是可以的。

下面是取消按钮的操作,以及_guid变量的定义:

void _frm_CloseEvent(object sender, EventArgs e)
        {
            button1.PerformClick();
        }
        private Guid _guid;
        private void button1_Click(object sender, EventArgs e)
        {
            if(_guid !=null)
            this.jcsAsyncComponet1.CancelAsync(_guid);
            this.Text = "Canceled!";
            if (_frm != null)
                _frm.Close();

        }

 

四.总结说明

    上面的代码虽然不是很完整,但已经基本上反映出来该组件的实现方法。因为只是范例,没有做更好的优化,在一些细节处理上或许还存在疏漏。感兴趣的朋友,也可以自己动手试上一试。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值