2017-01-25 9 views
0

私はWinforms exeを持っており、メニューからは、タスクとして低速実行プロセスを起動します。データを取得してからダイアログを表示するまでには約30秒かかります。通常、それはもはや返されません。私は例外をキャッチし、ログに何も表示されないので、それが正常に実行されていることがわかります。フォームは決して表示されず、CPU時間がかかっていないようです。しかし、私はデバッガでそれを実行し、コードをステップ実行し、正常に動作します。時々、より高速のPCで動作するように見えます。何が起こっている?Winforms async/awaitタスクが返されないようにする

private async void inPlayRecordToolStripMenuItem_Click(object sender, EventArgs e) 
    { 
     if (!GetClient()) return; 
     { 
      await Task.Run(() => 
      { 
       LaunchForm(); 
      }); 
     } 
    } 

    private async void LaunchForm() 
    { 
     try 
     { 
      { 
       var inPlayView = new InPlayView(); 
       await inPlayView.GetData(); 
       inPlayView.ShowDialog(); 
      } 
     } 
     catch (Exception ex) 
     { 
      Logger.LogMessage(ex.ToString()); 
     } 
    } 
+2

非同期メソッドは通常、「タスク」を返します。詳細については、[この回答](https://stackoverflow.com/questions/12144077/async-await-when-to-return-a-task-vs-void)を参照してください。 – Amy

+2

Task.RunはUIオブジェクトにアクセスしたり、ダイアログを作成したりしてはいけないバックグランドスレッド上でコードを実行しようとしています。 – RogerN

+0

ブレークポイントの設定を試しましたか?エラーメッセージが表示されますか? (私は 'InvalidOperationException'はスレッド間の問題のために期待しています。)' GetData() 'のコードを表示できますか? – Cameron

答えて

1

代わりにこれを行います。

private async void inPlayRecordToolStripMenuItem_Click(object sender, EventArgs e) 
{ 
    if (!GetClient()) return; 

    await LaunchForm(); 
} 

private async Task LaunchForm() 
{ 
    try 
    { 
     var inPlayView = new InPlayView(); 
     await inPlayView.GetData(); 
     inPlayView.ShowDialog(); 
    } 
    catch (Exception ex) 
    { 
     Logger.LogMessage(ex.ToString()); 
    } 
} 

あなたは既に非同期メソッドのTask.Run()をしたくない、と一般的なルールとして、async voidので、LaunchForm()イベントハンドラのみ大丈夫ではありません方法。

また、コメントとして指摘すると、Task.Run()はThreadPoolにタスクをキューイングするので、UIスレッドから終了します。

+1

これはより良い習慣ですが、これはOPの問題を説明するものではありません。 – Servy

+0

@Servy - 元のコードがなぜデバッガで動作するのか、時には説明していないのは間違いありません。私はそれがうまくいかないと思うだろう。おそらく、OPは私のバージョンを試して、それがどのように動作するかを教えてくれるでしょう。 – sellotape

+0

どうもありがとうございます。それは私のexeを非応答にするUIスレッドで実行されます。これがバックグラウンドで実行されている間、マウスのクリックに反応するようにします。私は非常に似たようなコードを持ついくつかの他のフォームを持っていると言わなければなりません、彼らはすべてうまく動作します、唯一の違いは、少し速いです。 –

0

自分のプロジェクトでasync/awaitを使用しましたが、タスクでShowDialogを実行する理由が考えられません。これがうまくいくかどうかはわかりませんが、あなたの流れを少し変更したいかもしれません。これにより、より一貫性があり、デバッグが容易になるはずです。

private async void inPlayRecordToolStripMenuItem_Click(object sender, EventArgs e) { 
    if (!GetClient()) { 
     return; 
    } 

    var playView = await LaunchForm(); 

    if (playView != null) { 
     playView.ShowDialog(); 
    } 
} 

private async Task<InPlayView> LaunchForm() { 
    try { 
     var inPlayView = new InPlayView(); 
     await inPlayView.GetData(); 

     return inPlayView; 
    } catch (Exception ex) { 
     // do cleanup of view if needed 
     Logger.LogMessage(ex.ToString()); 
     return null; 
    } 
} 
+0

ShowDialogはUIスレッドを結びつけませんか?私はタスクでShowDialogを行います。それ以外の場合は表示されません。 UIスレッドで表示するべきではありませんか? –

+0

'タイアップ'を意味する場合は、ユーザーの入力をブロックしてから「はい」を選択します。 ShowDialogは親ウィンドウの入力をブロックすることを想定しています(これは今や一番上のウィンドウです)。あなたがそれを望んでいなければ、Showを使います。 – Sean

関連する問題