简体   繁体   中英

Async Await UI Deadlock

I have a basic class for showing notifications that fades in (and out) with asynchronous delays in an attempt to keep the UI responsive.

 public partial class Notification : Form
{
    public Notification(string message)
    {
        InitializeComponent();
        txtNotification.Text = message;
    }

    async new public void Show()
    {
        FadeIn();
        await Task.Delay(7000);
        FadeOut();
    }

    async void FadeIn()
    {
        Opacity = 0;
        base.Show();
        while (Opacity < 1.0)
        {
            await Task.Delay(50);
            Opacity += 0.05;
        }
        Opacity = 1;
    }

    async void FadeOut()
    {
        while (Opacity > 0.0)
        {
            await Task.Delay(50);
            Opacity -= 0.05;
        }
        Opacity = 0;
        Hide();
    }
}

I also have a UI event handler that wants to perform some heavy lifting, then show a notification.

async public void MyHandler(args)
{
    await Task.Run(() => 
    {
            System.Diagnostics.Debug.WriteLine("Do something!");
    });
    new Notification("Work completed!").Show();
}

and I am running into deadlock during notification FadeIn 'await Task.Delay(50)'. I'm new to this async await malarkey but as I understand it I can't simply ConfigureAwait because I need to fade the notification in on the UI thread and I am using async and await 'all the way down' as it were. If I simply remove the line in the event handler that does the work then there is no deadlock, but I'm awaiting for it to complete so can't understand why I'm ending up in deadlock. Surely I've misunderstood something here?

As requested I've now removed the async void's and reduced the code:

 public partial class Notification : Form
{
    public Notification()
    {
        InitializeComponent();
    }

    async Task FadeIn()
    {
        Opacity = 0;
        base.Show();
        while (Opacity < 1.0)
        {
            await Task.Delay(50);
            Opacity += 0.05;
        }
    }
}

and I've discovered that the issue does not reproduce in a WinForm app, but does reproduce as described in an Outlook AddIn. For increased simplicity I'm now using the AddIn StartUp event and the following code shows the notification no problem

    async private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {            
        await new Notification().FadeIn();
    }

but this code causes hang/deadlock as I described previously

    async private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
        await Task.Run(() =>
       {
           System.Diagnostics.Debug.WriteLine("Do something!");
       });
        await new Notification().FadeIn();
    }

I've created a new AddIn, there is no other code, so I figure the problem must be Outlook.(?)

@StephenCleary provided the solution. Add the following line before the offending code.

SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM