I have the following code in my WPF application to call and wait for asnyc functions from a non-async function on the UI thread without blocking it. This is done by pumping messages in the background using DispatcherFrame:
public static void WaitWithPumping(this Task task)
{
if (task == null) throw new ArgumentNullException(“task”);
var nestedFrame = new DispatcherFrame();
task.ContinueWith(_ => nestedFrame.Continue = false);
Dispatcher.PushFrame(nestedFrame);
task.Wait();
}
public static T ResultWithPumping<T>(this Task<T> task)
{
if (task == null) throw new ArgumentNullException(“task”);
var nestedFrame = new DispatcherFrame();
task.ContinueWith(_ => nestedFrame.Continue = false);
Dispatcher.PushFrame(nestedFrame);
return task.Result;
}
I'd like to use something like this in my Xamarin Forms iOS/Android app to be able to work with the same codebase.
This is all needed because of a 3rdparty library which does not support async/await. For the same reason I cannot just use Task.Run() or ConfigureAwait(false) because the functions are needed to be run on the UI tread and I need to wait for the result before launching the next Task from the same blocking function.
public async void RunTaskOnUi1Async()
{
await ProcessAsync();
UpdateUiInner();
}
public async object RunTaskOnUi2Async()
{
var result = await ProcessAsync();
UpdateUiInner(result);
return result;
}
// Called from the UI thread
public void RunTasks()
{
UpdateUi();
RunTaskOnUi1Async().WaitWithPumping();
UpdateUi();
var result = RunTaskOnUi2Async().ResultWithPumping();
UpdateUi(result);
}
EDIT #1: Updated example. I know the example is a bit lame. Why don't I change RunTasks to async? Or just run ProcessAsync() on a background thread? Well, I am working on a legacy project (of course) and RunTasks is a LUA script processing engine which calls into my C# code and also manipulates UI directly so it must be run on the UI thread and it's non-async by design. Changing it would be a tremendous work. But the rest of my code is async and I was able to work around this problem in WPF easily by using the message pumping method.
Try the code below:
public static Task<T> BeginInvokeOnMainThreadAsync<T>(Func<T> a)
{
var tcs = new TaskCompletionSource<T>();
Device.BeginInvokeOnMainThread(() =>
{
try
{
var result = a();
tcs.SetResult(result);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
});
return tcs.Task;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.