2016-09-13 7 views
-1

入力フォームのStephen Clearyで問題を解決できました。更新3を参照してください。スレッドタイマーで非同期/待機しています

私は、非同期修飾子を持つメソッドを持つWindowsフォームアプリケーションを持っています。メソッドがボタンのクリックイベント内で呼び出された場合、UIスレッドはブロックされません。しかし、コールバックとしてタイマーの内部で呼び出すと、UIがフリーズします。私はここで間違っていることを理解できませんでした。私のコードの下を見てください。これはデモンストレーション目的のサンプルプロジェクトです。

public Form1() 
{ 
    InitializeComponent();    
} 

private async void formCloseAsync() 
{ 
    shutdown stf = new shutdown(); 
    stf.StartPosition = FormStartPosition.CenterScreen; 
    stf.Show(); 
    var task = Task.Factory.StartNew(processClose); 
    await task; 
} 

private void processClose() 
{ 
    Thread.Sleep(5000); 
    Environment.Exit(1); 
} 

private void simpleButtonAsync_Click(object sender, EventArgs e) 
{ 
    formCloseAsync(); 
}   

private void _simpleButtonTimer_Click(object sender, EventArgs e) 
{ 
    Timer _shutdownTimer = new Timer(delegate 
    { 
     formCloseAsync(); 
    }, null, 5000, Timeout.Infinite); 
} 

アップデート1:すべてのあなたの貴重な入力のための 感謝。下記の更新コードをご覧ください

public Form1() 
    { 
     InitializeComponent(); 

    } 

    private Timer _shutdownTimer; 
    private void formCloseAsync() 
    { 
     shutdown stf = new shutdown(); 
     stf.StartPosition = FormStartPosition.CenterScreen; 
     stf.Show(); 

     Task.Run(async()=> 
      { 
       await Task.Delay(5000); 
       Environment.Exit(1); 
      } 
     ); 
    } 

    private void simpleButtonAsync_Click(object sender, EventArgs e) 
    { 
     formCloseAsync(); 
    } 

    private void _simpleButtonTimer_Click(object sender, EventArgs e) 
    { 
     _shutdownTimer = new Timer(async delegate 
     { 
      formCloseAsync(); 
     }, null, 0, Timeout.Infinite); 
    } 

しかし、私はまだ同じ問題があります。シャットダウンstfはタイマーコールバックの内側で呼び出されるとブロックされます。メインのUIは大丈夫です。それに問題はない。私は、シャットダウン(stf)GUIがタイマーコールバックから作成されたときに応答するようにしたいだけです。シャットダウンGUIには進行状況バーがあります。

アップデート3:Thread.Sleepので

await Task.Delay(5000); 

実際ブロック現在のスレッドおよび非同期メソッド内で使用すべきではない。ここで

が最終コード

public partial class Form1 : Form 
{ 
    readonly shutdown _stf = new shutdown(); 
    public Form1() 
    { 
     InitializeComponent(); 

    } 

    private Timer _shutdownTimer; 
    private async Task formCloseAsync() 
    { 

     try 
     { 
      BeginInvoke(new MethodInvoker(delegate 
      { 

       _stf.StartPosition = FormStartPosition.CenterScreen; 
       _stf.Show(); 
      })); 
      await Task.Run(async() => 
          { 
           await Task.Delay(5000); 
          }); 

     } 
     catch (Exception ex) 
     { 

      MessageBox.Show(ex.ToString()); 

     } 
     finally 
     { 
      Environment.Exit(1); 
     } 

    } 

    private void simpleButtonAsync_Click(object sender, EventArgs e) 
    { 
     formCloseAsync(); 
    } 

    private void _simpleButtonTimer_Click(object sender, EventArgs e) 
    { 
     _shutdownTimer = new Timer(async delegate 
     { 
      formCloseAsync(); 
     }, null, 0, Timeout.Infinite); 
    } 

    private async void Form1_FormClosing(object sender, FormClosingEventArgs e) 
    { 
     e.Cancel = true; 
     await formCloseAsync(); 
    } 

答えて

1

はしかし、それは、UIをフリーズします。

バックグラウンドスレッドからUI要素にアクセスすることはできません(私はstf.Show();がダイアログを表示していると推測しています)。最も簡単な修正は、おそらくSystem.Threading.TimerWindows.Forms.Timerに置き換えることです。

その他の注意事項:

  • あなたはそのためのStartNewを使用しないでください。代わりにTask.Runを使用してください。私のブログ投稿StartNew is dangerousを参照してください。
  • イベントハンドラ以外にはasync voidを使用しないでください。私のMSDN記事Best Practices in Asynchronous Programmingを参照してください。
+0

こんにちは@stephenはあなたの入力に感謝します。元の投稿を更新しました。上記をご覧ください。どのUIがフリーズしているのか正しく言っていないかもしれません。 – IamaC

+0

@IamaC:同じ答えが適用されます。バックグラウンドスレッドからUIコードを実行しないでください。 –

+0

ありがとう@stephen。私はあなたの意見で問題を解決することができました。アップデート3をご覧ください – IamaC

5

使用Task.Delay代わりであります。

あなたはここにこのについての詳細を調べることができます:私はコールバックとしてタイマーの内側にそれを呼び出すときWhen to use Task.Delay, when to use Thread.Sleep?

+3

睡眠はバックグラウンドスレッドから呼び出されているので、それは彼の問題ではありません。彼はそれを変えなければならないが、彼は彼が持っていると主張している問題を引き起こさないだろう。 – Servy

+0

ありがとうございます。 – IamaC

関連する問題