【问题标题】:Winform is disposed while still awaiting a task during the FormClosing event [duplicate]在 FormClosing 事件期间仍在等待任务时处理 Winform [重复]
【发布时间】:2017-09-22 22:11:56
【问题描述】:

我想在 WinForms 应用程序中的 WinForm 的 FormClosing 事件期间进行一些清理。清理代码是异步的。

FormClosing 处理程序是:

private async void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    await DoCleanupAsync();

    // we never get here as the Form is disposed almost as soon as the async cleanup-method executes;
}

,与:

private async Task DoCleanupAsync()
{
    Console.WriteLine("stopping...");  // This is output
    await Task.Delay(2000);
    Console.WriteLine("stopped");      // This is not
}

正在发生的事情是在等待清理代码完成之前处理表单

顺便说一句,这会导致我在清理期间尝试更新表单(为简单起见,假设表单包含日志输出)的竞争条件,并且我收到 ObjectDisposedException,因为表单已被释放。

如果我在调用 Dispose() 时查看调用堆栈,我可以看到它被触发

System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage(ref System.Windows.Forms.Message m) 未知

,所以我们可以看到 dispose 是直接从 FormClosing 事件触发的,而我自己没有做任何事情。

我可以通过做一些 hacky 来解决这个问题:

private async void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    e.Cancel = true;
    await DoCleanupAsync();
    this.FormClosing -= Form1_FormClosing;
    Close();
}

,但我想了解实际情况!

【问题讨论】:

  • 您是否尝试过在e 上设置标志以防止在调用DoCleanupAsync() 之前关闭?
  • 当然。一旦您到达await,函数就会返回并从调用Form1_FormClosing 的位置继续执行。您似乎认为执行会暂停直到 DoCleanupAsync(); 完成,但这不是 await 的意思。
  • 您应该阅读更多关于 async/await 的工作原理的信息。然后你会自己找到答案。
  • 问题是事件不能/不会被等待。因此,即使DoCleanupAsync 仍在运行,就运行时而言,事件已经完成。这样表单的生命周期就结束了。

标签: c# winforms async-await dispose


【解决方案1】:

实际发生了什么

当您 await 使用 async 方法时,控制流将返回到您的 Form1_FormClosing 方法的调用者。而当你此时没有设置e.Cancel标志时,表单就关闭了。

DoCleanupAsync 返回的Task 完成后,处理程序的执行将恢复。但随后表单已经关闭。

【讨论】:

  • 谢谢——我真傻。我假设表单关闭事件的“调用者”也在等待 - 但鉴于返回类型为 void,这显然是不可能的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-15
  • 2012-07-13
  • 2012-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多