There is a problem with WPF when using asynchronous callbacks, the callback function needs to use a variable generated in the asynchronous function, such as the query database in the asynchronous function to get a DataTable, how to pass to the callback function?
"Scenario One" uses global variables
It is easy to think of using global variables, which is also the simplest way. But what if I want to iterate, for example, if the callback function determines that the DataTable has no data after the asynchronous function is executed , and the data continues to be asynchronous (BeginInvoke), then if a global variable is used, there might be an unexpected situation because it is a cyclic call. The DataTable used by the callback function is not the value you want.
"Solution two" closures
This is also a more conventional approach, the closure of the words to facilitate the internal variables passed, the following wording:
Private voidquerydatebase () {DataTable dttarget=NewDataTable ();//Shared VariablesAction Handler=Delegate()//Asynchronous Anonymous Delegate{dttarget=XXX Query database; }; AsyncCallback Functioncallback=Delegate(IAsyncResult Asyresult)//Callback Anonymous Delegate{handler. EndInvoke (Asyresult); if(DtTarget.Rows.Count >0) {querydatebase (); } }; Handler. BeginInvoke (Functioncallback,NULL); }
This is called closures, using anonymous delegates, callback functions and asynchronous functions defined in a method body, so that variables can be shared, similar to the WPF animation has a completed event, if it is used to start execution of some variables, you can also use this method to share variables. Here are two points to note:
- The handler registration method cannot involve any UI controls and UI logic, otherwise the Async method executes the EndInvoke method without completing the call, causing the calling error
- If you have to use UI controls or UI logic, you can use the Application.Current.Dispatcher.Invoke (New Action () () = {...}).
So, can we not use global variables?
"Scenario three" uses the return value
Use a delegate with a return value so that the return value of the delegate can be obtained when the delegate EndInvoke, and the code looks like this:
Public classStudent { PublicFunc<datatable>Queryhandler; PublicStudent () {Queryhandler=querydatebase; Queryhandler.begininvoke (CallBack,NULL); } PrivateDataTable Querydatebase () {DataTable Dttarget=XXX Check database; returnDttarget; } Private voidCallBack (IAsyncResult ar) {DataTable dtcallback=Queryhandler.endinvoke (AR); if(DtCallBack.Rows.Count >0) {Queryhandler.begininvoke (CallBack,NULL); } } }
Personally, this is a more orthodox notation, with precise return values and no global variables. In fact, the same is true of WinForm, it is not different, but WPF involves the UI to be aware of.
How the callback function gets the variables produced by the async function when the WPF asynchronous callback