I have been trying to setup a very basic method in my view models for temporarily freezing the UI thread while still pumping dispatcher messages, I have read this method will only work for simple cases and is not thread safe as 'waiting' for a task while already 'waiting' for a task causes buggy-ness.
But here is the method I wrote to do this so far:
public T WaitForTask<T>(Task<T> task, bool throwException = false)
{
WaitForTask((Task)task, throwException);
return (!task.IsCompleted || task.IsFaulted || task.Exception != null) ? default(T) : task.Result;
}
public void WaitForTask(Task task, bool throwException = false)
{
if (task == null)
throw new ArgumentNullException("task");
// Wait for the task to complete
IsWaiting = true;
using (MouseWait.Begin())
{
var runTask = UIDispatcher.InvokeAsync(async () =>
{
await task;
});
// Wait for the taske to finish
while (!task.IsCompleted)
{
DispatcherPush();
Thread.Sleep(10);
}
var exception = task.Exception;
if (exception != null)
{
if(exception is AggregateException)
{
var aggregateException = (AggregateException)exception;
log.ErrorFormat("{0}.WaitForTask(): {1}", GetType().Name, ExceptionUtility.JoinAggregateExceptionMessages(aggregateException));
}
else
{
var exceptionMessage = ExceptionUtility.JoinExceptionMessages(exception);
log.ErrorFormat("{0}.WaitForTask(): {1}", GetType().Name, exceptionMessage);
}
if (throwException)
throw exception;
}
}
IsWaiting = false;
}
This works fine for waiting for a single async task at a time which is all I need in my current applications scope, however when I began to optimize my async I found a number of places where using the Task.WhenAny()
method would be suitable. However calling Task.WhenAny()
causes the application to lock...
I think my issue might be related to the answer in this thread: C#/.NET 4.5 - Why does "await Task.WhenAny" never return when provided with a Task.Delay in a WPF application's UI thread?
Any suggestions would be appreciated.
Thanks, Alex.
You can achieve that with AsyncBridge. E.g.
It works by installing a custom
SynchronizationContext
and using that to wait for the task whilst freeing the UI thread.Because it is using synchronization context rather than using the dispatcher directly it is essentially framework agnostic and will work for both
WPF
and Winforms, which is why theSynchronizatonContext
concept was introduced. It basically abstracts how work is given to various threads.