2017-09-22 51 views
0

WinFormsアプリケーションでWinFormのFormClosingイベント中にいくつかのクリーンアップを行いたいと思います。クリーンアップコードは非同期です。WinFormsは、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 
} 

フォームはクリーンアップコードでawaitを前に処分されている完了です。

ちなみに、これは、クリーンアップ中にフォームを更新しようとしている競合状態を引き起こしています(単純にフォームにログ出力が含まれているとします)、フォームが破棄されたためObjectDisposedExceptionが発生します。

のDispose()が呼び出されたとき、私はコールスタックを見れば、私はそれは

のSystem.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage(REFからトリガされています見ることができますSystem.Windows.Forms.Message m)不明

したがって、disposeがFormClosingイベントから直接トリガされていることがわかります。自分で何もしていません。

私はハックのようなもの行うことによってこの問題を回避することができます

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

を、私は実際に何が起こっているのかを理解したいと思います!

+0

'DoCleanupAsync()'を呼び出す前に 'e'にフラグを立てて、閉じられないようにしましたか? – DiskJunky

+1

もちろん。 _await_に到達するとすぐに、関数が戻り、 'Form1_FormClosing'が呼び出された場所から実行が続けられます。 'DoCleanupAsync();'が終了するまで実行が停止すると思っているようですが、 'await'が意味するものではありません。 – oerkelens

+0

'async/await'の仕組みの詳細を読むべきです。それであなたは自分で答えを見つけるでしょう。 – dymanoid

答えて

1

実際

に何が起こっているのかいつawaitasync方法、あなたForm1_FormClosingメソッドの呼び出し元に制御が戻ります。そして、この時点でe.Cancelフラグを設定しなかった場合、フォームは閉じられます。

Taskが完了DoCleanupAsyncによって返されたときに、あなたのハンドラの実行が再開されました。しかし、フォームはすでに閉じています。

+0

ありがとう - 愚かな私。 Form-closingイベントの 'caller'も待っていると仮定していましたが、void型の戻り型の場合は明らかに不可能です – Ive

関連する問題