Как мне показать модальный диалог, который отслеживает задачу?

#c# #winforms #async-await

#c# #winforms #асинхронное ожидание

Вопрос:

Мне понятно, если у меня есть кнопка, которая запускает событие, но в приведенном ниже случае я хочу открыть диалоговое окно. Приведенный ниже код представляет собой беспорядок, я не знаю, как это сделать правильно. Я думаю, что async / await является частью этого, но я не совсем понимаю этот случай.

 class TaskObject : Form
{
    public void MyFunc()
    { 
      MyDialog d = new MyDialog(this);
      d.ShowDialog(); // I don't want any other interaction except this dialog's controls
    }
    internal async Task<bool> LongFunction()
    {
      // ...
      return true;
    }

}
class MyDialog : Form
{
  Task<bool> task;
  public async MyDialog(TaskObject o)
  {
     task = new Task<bool>(o.LongFunction);
     await task;
  }
  void when_LongFunction_does_something_interesting()
  {
    this.MyTextBox.Text = "Something interesting";
  }
  void when_task_completes()
  {
     this.CancelButton.Visible = false;
     this.CloseButton.Visible = true;
  }
}
  

Комментарии:

1. Оно вызывается ShowDialog() , а не ShowModal() .

2. Что? Мой вопрос на 100% отличается, Ахмед. Речь идет о том, как заставить диалог работать параллельно с запущенной задачей.

3. «Это о том, как заставить диалог работать параллельно с запущенной задачей». Где выполняется эта задача? В «родительской» форме?

4. Видишь конструктор? Это создание задачи и ее выполнение. Но этот код не компилируется. Я хочу, чтобы диалоговое окно запускалось во время выполнения фоновой задачи, а затем задача вызывала диалоговое окно для выполнения каких-либо действий.

5. Предполагая, что TaskObject является производным от Form и LongFunction является общедоступным / внутренним методом в o экземпляре этой формы, вы можете просто сделать этот метод асинхронным, а затем вызвать его (и await это) в модальной форме. форма. Вы пробовали это? Пожалуйста, включите LongFunction метод в свой вопрос (или, по крайней мере, подпись этого метода).

Ответ №1:

Здесь есть два момента:

  1. Конструктор вашей формы не может иметь async модификатор. В качестве альтернативы вы можете использовать вместо этого Load событие.

  2. (Необязательно) Вам не нужно передавать экземпляр «родительской» формы конструктору, вы можете получить его непосредственно из Owner свойства, если используете ShowDialog(this) вместо ShowDialog() .

Кроме того, не забудьте удалить любую диалоговую форму после того, как вы закончите с ней. Желательно, чтобы его использование было заключено в using блок.

Вот как я бы это сделал; В TaskObject форме:

 internal async Task<bool> LongFunction()
{
    // Do some magic.
    // await ...

    return true;
}

public void MyFunc()
{
    using (MyDialog d = new MyDialog())
    {
        d.ShowDialog(this);
    }
}
  

В MyDialog форме:

 private async void MyDialog_Load(object sender, EventArgs e)
{
    TaskObject owner = this.Owner as TaskObject;
    await owner.LongFunction();
    when_task_completes();
}
  

Если вы также хотите отслеживать ход выполнения LongFunction , вы можете добавить к нему Progress<T> параметр и использовать его следующим образом:

 internal async Task<bool> LongFunction(IProgress<string> progress)
{
    // Do some magic.
    progress.Report("Something interesting");
    // await ...
    // More magic.
    return true;
}
  

Тогда вы можете сделать что-то вроде этого:

 private async void MyDialog_Load(object sender, EventArgs e)
{
    TaskObject owner = this.Owner as TaskObject;

    var progress = new Progress<string>(s => when_LongFunction_does_something_interesting(s));
    await owner.LongFunction(progress);
    when_task_completes();
}

void when_LongFunction_does_something_interesting(string message)
{
    this.MyTextBox.Text = message;
}
  

Обратите внимание, что я использовал Progress<string> в качестве примера. Вместо string вы можете использовать любой тип, который лучше всего подходит для вашей ситуации.

Комментарии:

1. Большое вам спасибо за усилия, которые вы приложили, чтобы помочь мне. Я сейчас пробую это, и если это сработает, поставлю галочку.

2. Обновление: в итоге я отказался от стиля async / await. Вместо этого диалоговое окно запускает код в отдельно управляемом потоке (поэтому функция диалога может просто вернуться), и этот код вызовет диалоговое окно для выполнения обновлений. Итак, к сожалению, полный тест невозможен, но, по крайней мере, часть о событии загрузки все еще полезна для меня. Еще раз спасибо!