I currently have some code to help execute async code on the main thread using DispatcherQueue in a WinUI 3 application using .Net 7.
// Note that this is a simplified version of the original code, for brevity.
public static async Task Execute(this DispatcherQueue dispatcher, Func<Task> function)
{
if (dispatcher.HasThreadAccess)
{
await function();
}
else
{
var taskCompletionSource = new TaskCompletionSource<bool>();
dispatcher.TryEnqueue(ExecuteUI);
await taskCompletionSource.Task;
}
static async void ExecuteUI()
{
try
{
await function();
taskCompletionSource.SetResult(true);
}
catch (Exception e)
{
taskCompletionSource.SetException(e);
}
}
}
What would be the best way to implement this feature without using async void?
Edit:
I understand that the DispatcherQueue.TryEnqueue overloads take Action or Func parameters that are not returning Task. My question in about about bridging that sync-to-async gap with a solution that complies with this rule.
Rule #4. Never define
async voidmethods. Make the methods returnTaskinstead.
- Exceptions thrown from
async voidmethods always crash the process.- Callers don't even have the option to
awaitthe result.- Exceptions can't be reported to telemetry by the caller.
- It's impossible for your VS package to responsibly block in
Package.Closetill yourasyncwork is done when it was kicked off this way.- Be cautious:
async delegateorasync () =>becomeasync voidmethods when passed to a method that acceptsActiondelegates. Only passasyncdelegates to methods that acceptFunc<Task>orFunc<Task<T>>parameters.
Install the CommunityToolkit.WinUI NuGet package and use one of the overloads of the
EnqueueAsyncmethod that accept aFunc<Task>orFunc<Task<T>>.The source code for these methods are available on GitHub.