异步ShowDialog

dav*_*der 16 c# asynchronous async-await

我正在使用异步/等待从数据库异步加载我的数据,在加载过程中,我想弹出一个加载表单,它只是一个带有运行进度条的简单表单,表示有一个正在运行的进程.加载数据后,对话框将自动关闭.我怎样才能做到这一点?以下是我目前的代码:

 protected async void LoadData() 
    {
       ProgressForm _progress = new ProgressForm();  
       _progress.ShowDialog()  // not working
       var data = await GetData();          
       _progress.Close();
    }
Run Code Online (Sandbox Code Playgroud)

更新:

我设法通过更改代码来使其工作:

 protected async void LoadData() 
        {
           ProgressForm _progress = new ProgressForm();  
           _progress.BeginInvoke(new System.Action(()=>_progress.ShowDialog()));
           var data = await GetData();          
           _progress.Close();
        }
Run Code Online (Sandbox Code Playgroud)

这是正确的方式还是有更好的方法?

谢谢你的帮助.

nos*_*tio 12

Task.Yield像这样很容易实现(WinForms,为简单起见,没有异常处理):

namespace WinFormsApp
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        async Task<int> LoadDataAsync()
        {
            await Task.Delay(2000);
            return 42;
        }

        private async void button1_Click(object sender, EventArgs e)
        {
            var progressForm = new Form() { 
                Width = 300, Height = 100, Text = "Please wait... " };

            var progressFormTask = progressForm.ShowDialogAsync();

            var data = await LoadDataAsync();

            progressForm.Close();
            await progressFormTask;

            MessageBox.Show(data.ToString());
        }
    }

    internal static class DialogExt
    {
        public static async Task<DialogResult> ShowDialogAsync(this Form @this)
        {
            await Task.Yield();
            if (@this.IsDisposed)
                return DialogResult.OK;
            return @this.ShowDialog();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

重要的是要理解执行流如何跳转到新的嵌套消息循环(模式对话框的循环),然后返回到原始消息循环(这await progressFormTask就是用于).

  • 我应该回报你的好意,并为你这个出色的回答提供一点小小的奖励。我仍然对你如何想出这个有效、简单且完全不直观的解决方案感到困惑! (2认同)
  • @TheodorZoulias,谢谢,很高兴收到这样的反馈 :) 我想我只是碰巧在早期大量参与了 COM + 桌面应用程序开发,所以我有机会学习一两件事关于如何消息循环和泵送在 Windows 和 .NET 下工作。如今它的相关性要低得多,但我仍然会不断地回顾一些隐藏的宝藏,比如[这个](https://docs.microsoft.com/en-us/archive/blogs/cbrumme/apartments-并泵入 clr)。安息吧,Chris Brumme,该博客的作者......:( (2认同)
  • @MarkA.Donohoe,我认为你的建议是有道理的,当时我没有测试这个片段的所有代码路径。这些天,我没有做太多的 WinForms/WPF 开发,但我要接触这段代码,我可能会更改它以在“IsDispose”为“true”时抛出异常。我仍然会检查它,因为理论上,在“Task.Yield()”之后异步代码流继续之前,表单可能会关闭。 (2认同)

Bra*_*ith 1

ShowDialog()是一个阻塞调用;await在用户关闭对话框之前,执行不会前进到该语句。Show()代替使用。不幸的是,您的对话框不是模态的,但它会正确跟踪异步操作的进度。

  • 不幸的是,由于某些原因我必须使用 ShowDialog() 。不管怎么说,多谢拉。 (3认同)