This answer is designed for anyone who is using WPF for .NET 4.5.
If you attempt to execute Task.Run()
on the GUI thread, then task.Wait()
will hang indefinitely, if you do not have the async
keyword in your function definition.
This extension method solves the problem by checking to see if we are on the GUI thread, and if so, running the task on the WPF dispatcher thread.
This class can act as the glue between the async/await world and the non-async/await world, in situations where it is unavoidable, such as MVVM properties or dependencies on other APIs that do not use async/await.
/// <summary>
/// Intent: runs an async/await task synchronously. Designed for use with WPF.
/// Normally, under WPF, if task.Wait() is executed on the GUI thread without async
/// in the function signature, it will hang with a threading deadlock, this class
/// solves that problem.
/// </summary>
public static class TaskHelper
{
public static void MyRunTaskSynchronously(this Task task)
{
if (MyIfWpfDispatcherThread)
{
var result = Dispatcher.CurrentDispatcher.InvokeAsync(async () => { await task; });
result.Wait();
if (result.Status != DispatcherOperationStatus.Completed)
{
throw new Exception("Error E99213. Task did not run to completion.");
}
}
else
{
task.Wait();
if (task.Status != TaskStatus.RanToCompletion)
{
throw new Exception("Error E33213. Task did not run to completion.");
}
}
}
public static T MyRunTaskSynchronously<T>(this Task<T> task)
{
if (MyIfWpfDispatcherThread)
{
T res = default(T);
var result = Dispatcher.CurrentDispatcher.InvokeAsync(async () => { res = await task; });
result.Wait();
if (result.Status != DispatcherOperationStatus.Completed)
{
throw new Exception("Error E89213. Task did not run to completion.");
}
return res;
}
else
{
T res = default(T);
var result = Task.Run(async () => res = await task);
result.Wait();
if (result.Status != TaskStatus.RanToCompletion)
{
throw new Exception("Error E12823. Task did not run to completion.");
}
return res;
}
}
/// <summary>
/// If the task is running on the WPF dispatcher thread.
/// </summary>
public static bool MyIfWpfDispatcherThread
{
get
{
return Application.Current.Dispatcher.CheckAccess();
}
}
}