Задание держать экземпляр формы открытым? - PullRequest
3 голосов
/ 13 марта 2012

У меня есть форма Windows, которая открывает другую форму. Во вторичной форме он запускает задачу асинхронно. Если пользователь запускает задачу, а затем отменяет ее и быстро закрывает форму, форма удаляется и устанавливается равной нулю, однако, когда задача возвращается из отмененной, я все равно получаю MessageBox.Show произойдет

public class MyMainForm : Form
{
  public void OpenChildForm()
  {
     MyChildForm form = new MyChildForm();
     form.ShowDialog();
     form.Dispose();
     form = null;
  }
}

public class MyChildForm : Form
{

  private CancellationTokenSource MyTokensource;
  private Task task; 


  public void StartTask()
  {
     MyTokensource = new CancellationTokenSource();
     task = Task.Factory.StartNew(() => MyMethod(MyTokensource.Token), MyTokensource.Token);
  }

  public void MyMethod(CancellationToken token)
  {
      var result = StaticClass.DoSomethingLengthy(token);  //The cancel make take a couple of seconds to return here
      if (result == Cancelled)
      {
         MessageBox.Show("Cancelled");
         UpdateLabel("Cancelled")
       }
  }

  public void ButtonClose_Click()
  { 
    if (task != null && !task.IsCompleted)
    {
      MyTokensource.Cancel();
    }
    this.Close();
  }
}

Ответы [ 5 ]

2 голосов
/ 13 марта 2012

форма удалена и установлена ​​в ноль, однако, когда задача возвращается из отмененной, я все еще получаю MessageBox.Show происходит

Установка переменной, которая является ссылкой на формуnull, и даже вызов Dispose () для формы, на самом деле не уничтожает форму.Задача все еще выполняется до тех пор, пока она не будет отменена (CancellationTokenSource задуман как кооперативная модель для отмены).

Таким образом, вам необходимо явно обработать путь к коду, который происходит при отмене задачи.Это может быть так же просто, как проверка, если вы уже утилизированы, например:

if (this.IsDisposed)
    return; // Just break out if we canceled and shut down

// Your other code....
if (result == Cancelled)
    MessageBox.Show("Cancelled");
2 голосов
/ 13 марта 2012

Это имеет смысл. Task отключено, асинхронное выполнение, время его выполнения не привязано к времени жизни Form. Вам просто нужно добавить явную проверку, чтобы убедиться, что вы не показываете MessageBox, если Form уже утилизируется:

if(result == Cancelled
            &&
   !(this.Disposing
           ||
    this.IsDisposed))
{
    MessageBox.Show("Cancelled");
}
1 голос
/ 13 марта 2012

Еще одна вещь, на которую следует обратить внимание: убедитесь, что вы не звоните StartTask() более одного раза.

Если это так, вы получаете несколько асинхронных задач и несколько экземпляров CancellationTokenSource(из которых только один все еще упоминается формой).

0 голосов
/ 13 марта 2012

ГХ, возможно, не собрал форму, несмотря на то, что вы звоните Dispose() и устанавливаете ссылку на ноль. Это нормально, поскольку GC недетерминирован.

Благодаря реализации IDisposable вы можете проверить свойства IsDisposed и IsDisposing в форме, чтобы узнать, был ли метод Dispose() уже вызван или находится в процессе запуска.

0 голосов
/ 13 марта 2012

Экземпляр формы все еще там, хотя окно может быть невидимым.Чтобы убедиться, что MessageBox не отображается после закрытия формы, добавьте событие в OnClosing и установите переменную-член m_formClosed в true.Показывать сообщение, только когда переменная-член false.

if (result == Cancelled && !m_formClosed)
    MessageBox.Show("Cancelled");
...