异步等待UI死锁

本文关键字:死锁 UI 等待 异步 | 更新日期: 2023-09-27 18:01:48

我有一个基本的类,用于显示带有异步延迟的淡入(淡出)通知,以保持UI响应。

 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();
    }
}

我也有一个UI事件处理程序,想要执行一些繁重的工作,然后显示一个通知。

async public void MyHandler(args)
{
    await Task.Run(() => 
    {
            System.Diagnostics.Debug.WriteLine("Do something!");
    });
    new Notification("Work completed!").Show();
}
在通知FadeIn 'await Task.Delay(50)'期间,我遇到了死锁。我是新的这个异步等待的废话,但据我所知,我不能简单地配置等待,因为我需要在UI线程上淡化通知,我正在使用异步和等待"一路下来",因为它是。如果我只是删除事件处理程序中执行该工作的行,那么就没有死锁,但是我正在等待它完成,因此无法理解为什么我最终会陷入死锁。我肯定是误解了什么吧?

根据要求,我现在已经删除了async void's并减少了代码:

 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;
        }
    }
}

,我发现这个问题不会在WinForm应用程序中重现,但会像Outlook插件中描述的那样重现。为了增加简单性,我现在使用AddIn StartUp事件,下面的代码显示了通知no problem

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

但是这段代码会导致挂起/死锁,正如我之前描述的

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

我已经创建了一个新的插件,没有其他代码,所以我认为问题一定是Outlook。(?)

异步等待UI死锁

@StephenCleary提供了解决方案。在有问题的代码之前添加以下行。

SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());