Search code examples
c#async-awaitevent-handling.net-4.8microsoft.visualstudio.threading

Correct way to handle event on main thread


Usually when I want to handle an event on the main thread that has been invoked in a background thread, I write the following:

_backgroundWork.BackgroundEvent += (sender, args) => DoSomethingForUI();

private void DoSomethingForUI()
{
    Application.Current.Dispatcher.Invoke(new Action(() => { /* Something for UI */ }));
}

However, when using the Microsoft.VisualStudio.Threading.Analyzers, I get a warning that Invoke is a legacy thread switching method and I should do the following:

_backgroundWork.BackgroundEvent += (sender, args) => DoSomethingForUI();

private async void DoSomethingForUI()
{
    await _joinableTaskFactory.SwitchToMainThreadAsync();
    /* Do something for UI */
}

This gets rid of the warning but produces a new warning that I shouldn't use async void but instead should use the following:

_backgroundWork.BackgroundEvent += (sender, args) => DoSomethingForUI();

private void DoSomethingForUI()
{
    _joinableTaskFactory.RunAsync(async () =>
    {
        await _joinableTaskFactory.SwitchToMainThreadAsync();
        /* Do something for UI */
    });
}

Again, this gets rid of the warning but produces another warning. I got rid of that warning by doing the following:

_backgroundWork.BackgroundEvent += (sender, args) => DoSomethingForUI();

private void DoSomethingForUI()
{
    _joinableTaskFactory.Run(async () =>
    {
        await _joinableTaskFactory.SwitchToMainThreadAsync();
        /* Do something for UI */
    });
}

This produces yet another warning, however that one doesn't sound as bad as the others.

I am still confused. What is the correct way to handle a background event on the main thread?


Solution

  • To get rid of all warnings, the following works:

    _backgroundWork.BackgroundEvent += (sender, args) => _joinableTaskFactory.Run(() => DoSomethingForUIAsync());
    
    private async Task DoSomethingForUIAsync()
    {
        await _joinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true);
        /* Do something for UI */
    }