首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >异步ShowDialog

异步ShowDialog
EN

Stack Overflow用户
提问于 2015-10-29 05:58:41
回答 5查看 26.3K关注 0票数 23

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

代码语言:javascript
复制
 protected async void LoadData() 
    {
       ProgressForm _progress = new ProgressForm();  
       _progress.ShowDialog()  // not working
       var data = await GetData();          
       _progress.Close();
    }

更新:

通过更改代码,我设法使它正常工作:

代码语言:javascript
复制
 protected async void LoadData() 
        {
           ProgressForm _progress = new ProgressForm();  
           _progress.BeginInvoke(new System.Action(()=>_progress.ShowDialog()));
           var data = await GetData();          
           _progress.Close();
        }

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

谢谢你的帮助。

EN

回答 5

Stack Overflow用户

发布于 2015-10-29 09:58:33

使用Task.Yield很容易实现,如下所示(WinForms,为简单起见没有异常处理)。了解执行流在这里如何跳到新的嵌套消息循环(模态对话框的消息循环),然后返回到原始消息循环(这就是await progressFormTask的作用)是很重要的:

代码语言:javascript
复制
namespace WinFormsApp
{
  internal static class DialogExt
  {
    public static async Task<DialogResult> ShowDialogAsync(this Form @this)
    {
      await Task.Yield();
      if (@this.IsDisposed)
        return DialogResult.Cancel;
      return @this.ShowDialog();
    }
  }

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

      object data;
      var progressFormTask = progressForm.ShowDialogAsync();
      try 
      {
        data = await LoadDataAsync();
      }
      finally 
      {
        progressForm.Close();
        await progressFormTask;
      }

      // we got the data and the progress dialog is closed here
      MessageBox.Show(data.ToString());
    }
  }
}
票数 36
EN

Stack Overflow用户

发布于 2017-04-14 22:36:01

下面是一种使用Task.ContinueWith的模式,在使用模态ProgressForm时应该避免任何争用条件:

代码语言:javascript
复制
protected async void LoadDataAsync()
{
    var progressForm = 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(() =>
        {   
            progressForm.ShowDialog();
        }));
        
        // Begin long-running method here
        LoadData();
    })).ContinueWith(new Action<Task>(task => 
    {
        // Close modal dialog
        // No need to use BeginInvoke here
        //   because ContinueWith was called with TaskScheduler.FromCurrentSynchronizationContext()
        progressForm.Close();
    }), TaskScheduler.FromCurrentSynchronizationContext());
}
票数 4
EN

Stack Overflow用户

发布于 2015-10-29 06:03:48

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33406939

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档