首页 > 代码库 > WPF异步回调时回调函数如何获取异步函数产生的变量

WPF异步回调时回调函数如何获取异步函数产生的变量

  有这么一个问题,WPF在使用异步回调的时候,回调函数需要用到异步函数里产生的一个变量,例如异步函数里查询数据库得到了一个DataTable,如何传递给回调函数呢?

【方案一】使用全局变量

  很容易想到的是用全局变量,这也是最简单的办法。但是如果我想循环调用呢,例如回调函数判断异步函数执行完之后的DataTable有没有数据,有数据则继续异步(BeginInvoke),这时候如果使用全局变量可能会出现意外情况,因为是循环调用,回调函数使用的DataTable是不是你想要的那个值就比较难说了。

【方案二】闭包

  这也是一个比较常规的办法,闭包的话就方便内部变量传递了,写法如下:

private void QueryDateBase()
        {
            DataTable dtTarget = new DataTable();//共享变量

            Action handler = delegate()//异步匿名委托
            {
                dtTarget = XXX查询数据库;
            };
            
            AsyncCallback functionCallBack = delegate(IAsyncResult asyResult)//回调匿名委托
            {
                handler.EndInvoke(asyResult);
                if (dtTarget.Rows.Count > 0)
                {
                    QueryDateBase();
                }
            };

            handler.BeginInvoke(functionCallBack, null);
        }
  这就是所谓的闭包了,使用了匿名委托,回调函数和异步函数定义在一个方法体内,这样变量就能共享,类似的,WPF的动画有个Completed事件,如果它里面要使用到开始执行时的一些变量,也能使用此法共享变量。这里有两点要注意:
  1. handler注册的方法里不能涉及到任何UI控件和UI逻辑,否则异步方法没有调用完就会执行EndInvoke方法,导致调用错误
  2. 如果必须要用到UI控件或者UI逻辑,可以用Application.Current.Dispatcher.Invoke(new Action(() => { ...}));

  那么,能不能不使用全局变量呢?

【方案三】使用返回值

  使用带返回值的委托,这样在委托EndInvoke的时候就可以获得委托的返回值了,代码看起来是这样的:

    public class Student
    {
        public Func<DataTable> queryHandler;

        public Student()
        {
            queryHandler = QueryDateBase;
            queryHandler.BeginInvoke(CallBack, null);
        }

        private DataTable QueryDateBase()
        {
            DataTable dtTarget = XXX查数据库;
            return dtTarget;
        }

        private void CallBack(IAsyncResult ar)
        {
            DataTable dtCallBack = queryHandler.EndInvoke(ar);
            if (dtCallBack.Rows.Count > 0)
            {
                queryHandler.BeginInvoke(CallBack, null);
            }
        }
    }
  个人认为这是比较正统的写法,精准的返回值,没有全局变量。其实Winform也是如此,使用起来并无差异,只是wpf涉及UI时要注意。

WPF异步回调时回调函数如何获取异步函数产生的变量