异步ShowDialog

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

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

更新:

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

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

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

谢谢你的帮助。

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

 namespace WinFormsApp { public partial class MainForm : Form { public MainForm() { InitializeComponent(); } async Task 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 ShowDialogAsync(this Form @this) { await Task.Yield(); if (@this.IsDisposed) return DialogResult.OK; return @this.ShowDialog(); } } } 

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

这是一个使用Task.ContinueWith的表单,应该避免使用模态ProgressForm的任何竞争条件:

 protected async void LoadDataAsync() { ProgressForm _progress = new ProgressForm(); // 'await' long-running method by wrapping inside Task.Run await Task.Run(new Action(() => { // Display dialog modally // - Use BeginInvoke here to avoid blocking // and illegal cross threading exception this.BeginInvoke(new Action(() => { _progress.ShowDialog(); })); // Begin long-running method here LoadData(); })).ContinueWith(new Action(task => { // Close modal dialog // - No need to use BeginInvoke here // because ContinueWith was called with TaskScheduler.FromCurrentSynchronizationContext() _progress.Close(); }), TaskScheduler.FromCurrentSynchronizationContext()); } 

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

您可以尝试以下方法:

 protected async void LoadData() { ProgressForm _progress = new ProgressForm(); var loadDataTask = GetData(); loadDataTask.ContinueWith(a => this.Invoke((MethodInvoker)delegate { _progress.Close(); })); _progress.ShowDialog(); }