/// <summary> /// Runs the function inside a message loop and continues pumping messages /// until the returned task completes. /// </summary> /// <returns>The completed task returned by the delegate's invocation</returns> public static Task Run(Func <Task> function) { using (SynchronizationContextSwitcher.Capture()) { Dispatcher dispatcher = Dispatcher.CurrentDispatcher; DispatcherFrame frame = new DispatcherFrame(exitWhenRequested: true); var message = new TaskFunctionLaunchMessage(function, dispatcher, frame); // queue up our first message before we run the loop dispatcher.BeginInvoke(new Action(message.LaunchMessageImpl)); // run the actual WPF message loop Dispatcher.PushFrame(frame); // PushFrame() has returned. Because we set Contine = false // in a continuation of the task, this can only occur if the task // has also completed. if (message.ReturnedTask != null) { message.ReturnedTask.RethrowForCompletedTasks(); } return(message.ReturnedTask); } }
public static Task Run(Func <Task> asyncMethod) { using (SynchronizationContextSwitcher.Capture()) { var customContext = new Context(); SynchronizationContext.SetSynchronizationContext(customContext); var task = asyncMethod.Invoke(); if (task != null) { // register a continuation with the task, which will shut down the loop when the task completes. task.ContinueWith(_ => customContext.WorkQueue.Shutdown(), TaskContinuationOptions.ExecuteSynchronously); } else { // the delegate returned a null Task (VB/C# compilers never do this for async methods) // we don't have anything to register continuations with in this case, so just return immediately return(task); } customContext.WorkQueue.ExecuteWorkQueueLoop(); task.RethrowForCompletedTasks(); return(task); } }
/// <summary> /// Runs the action inside a message loop and continues looping work items /// as long as any asynchronous operations have been registered /// </summary> public static void Run(Action asyncAction) { using (SynchronizationContextSwitcher.Capture()) { var customContext = new VoidContext(); SynchronizationContext.SetSynchronizationContext(customContext); // Do an explicit increment/decrement. // Our sync context does a check on decrement, to see if there are any // outstanding asynchronous operations (async void methods register this correctly). // If there aren't any registerd operations, then it will exit the loop customContext.OperationStarted(); try { asyncAction.Invoke(); } finally { customContext.OperationCompleted(); } customContext.WorkQueue.ExecuteWorkQueueLoop(); // ExecuteWorkQueueLoop() has returned. This must indicate that // the operation count has fallen back to zero. } }
/// <summary> /// Runs the action inside a message loop and continues pumping messages /// as long as any asynchronous operations have been registered /// </summary> public static void Run(Action asyncAction) { using (SynchronizationContextSwitcher.Capture()) { Dispatcher dispatcher = Dispatcher.CurrentDispatcher; DispatcherFrame frame = new DispatcherFrame(exitWhenRequested: true); var message = new AsyncActionLaunchMessage(asyncAction, dispatcher, frame); // queue up our first message before we run the loop dispatcher.BeginInvoke(new Action(message.LaunchMessageImpl)); // run the actual WPF message loop Dispatcher.PushFrame(frame); // PushFrame() has returned. This must indicate that // the operation count has fallen back to zero. } }