0

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.(?)

Eugene Astafiev
  • 47,483
  • 3
  • 24
  • 45
Russell Horwood
  • 1,015
  • 1
  • 11
  • 19
  • 2
    There is nothing here that I see that can cause a deadlock. Is this really what you're running? – Yuval Itzchakov Jul 09 '15 at 16:54
  • 3
    You should probably not do this `async void FadeOut()`. Use `async Task FadeOut()` instead. –  Jul 09 '15 at 17:06
  • @YuvalItzchakov This is very close to what I'm running. The notification class is exact. The handler is a ribbon xml control handler. Maybe it's not a deadlock but execution ends/hangs indefinitely at 'await Task.Delay(50);' in FadeIn, unless I remove the line immediately before 'new Notification("Work completed!").Show();'. – Russell Horwood Jul 09 '15 at 17:18
  • I suggest you read this: http://stackoverflow.com/a/12144426/5089754 and this https://msdn.microsoft.com/en-us/magazine/jj991977.aspx –  Jul 09 '15 at 17:24
  • 4
    1) Avoid `async void`. 2) Please post a minimal, reproducible example. – Stephen Cleary Jul 09 '15 at 17:33
  • Agreed with other comments that there is no deadlock in the code you showed. It must be in the code you didn't show. Please provide [a good, _minimal_, _complete_ code example](https://stackoverflow.com/help/mcve) that reliably reproduces the problem. – Peter Duniho Jul 10 '15 at 02:18
  • @StephenCleary I have now removed async void and the I'm showing all the code, this is the exact code that I'm running and it does reliably reproduce a deadlock from inside an Outlook Add-In. – Russell Horwood Jul 10 '15 at 09:53
  • 2
    @RussellHorwood: Try adding this as the first line of `ThisAddIn_Startup`: `SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());` – Stephen Cleary Jul 10 '15 at 12:28

1 Answers1

0

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

SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());
Russell Horwood
  • 1,015
  • 1
  • 11
  • 19