在FormClosing事件期间仍在等待任务时处置Winform

时间:2017-09-22 14:07:13

标签: c# winforms async-await dispose

我想在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()时查看callstack,我可以看到它是从

触发的

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

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

我可以做一些像hacky这样的事情来解决这个问题:

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

,但我想了解实际发生了什么!

1 个答案:

答案 0 :(得分:1)

  

实际上是什么

当您await async方法时,控制流会返回到Form1_FormClosing方法的调用方。当您此时未设置e.Cancel标志时,表单将被关闭。

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