2009-06-11 19 views
4

これはおそらく愚かな質問ですが、私はstackoverflowで答えを見つけることができませんでした。Winforms UIをバックグラウンドスレッドの結果から更新する

フォームを表示するためにスレッドを実行して結果を表示するWinformアプリケーションでボタンクリックイベントが発生しました。

スレッドが結果を計算したときにフォームUIを更新するにはどうすればよいですか?

private void btnRequestR2Approval_Click(object sender, EventArgs e) 
    { 
     if (User.IsLogged) 
     { 
      ValidationResults results = new ValidationResults(); 
      results.Show(); 

      Logger log = Logger.Instance(); 
      Logger.NewLogAddedHandler messageDelegate = new Logger.NewLogAddedHandler(results.NewLogMessage); 

      if (!log.IsEventHandlerRegistered()) 
      { 
       log.NewLogAdded += messageDelegate; 
      } 

      ThreadStart operation = new ThreadStart(ValidateAndSubmit); 
      Thread theThread = new Thread(operation); 
      theThread.Start(); 

     } 
     else 
     { 
      MessageBox.Show("Please login"); 
     } 

    } 

あなたはどちらか 1.呼び出し元のスレッドをブロックするtheThread.Join()を行うことができ、あなたに

+0

ASPについて質問していますか。NET(Webテクノロジ)またはWinforms(Windowsネイティブテクノロジ)?あなたはWinFormsを使用しているように見えますが、タイトルとタグは別の方法を示唆しています。 – jrcs3

+1

「終了しました」とはどういう意味ですか?スレッドが終了したこと、またはスレッドがあなたが知る必要があるものを計算したことを確認しますか? –

+0

は実行を終了し、スレッドが何かを計算したことを意味し、別のスレッドで何かをリフレッシュする必要があります。 – Sergey

答えて

13

WinFormsでバックグラウンドタスクを実行する最も簡単な方法は、BackgroundWorkerを使用することです。

  • フォームにドロップします。
  • イベントを配線します。最低限、DoWorkを使用してください。おそらくRunWorkerCompletedが必要になります。
  • バックグラウンドタスクをDoWorkイベントに書き込みます。
  • RunWorkerCompletedイベントでUIの変更を書き込む。
  • backgroundWorker1.RunWorkerAsync();を呼び出すと、恐らくいくつかのボタンハンドラから処理が開始されます。

BackgroundWorkerを使用すると、すべての厄介なスレッド処理とIsInvokeRequiredが回避されます。

詳細はhow-to articleです。

0

ありがとうございます。 2.最初のスレッドを2番目のスレッドに渡して、メインスレッドにコールバックします。Invoke()を実行する必要があるため、フォームを再描画できます。

私は不思議です。 Asp.Net(WebForms)またはWinFormsを使用していますか?あなたがウェブでこれをやろうとしているのであれば、完全に異なるアプローチが必要です。

+0

Winフォーム、そして私はtheThread.Join()を使って試してみましたが、アプリケーション全体をロックしています。 – Sergey

+0

スレッドが完了するまでThread.Joinが待機するので、これはまさにあなたが求めていたものです。これがあなたが意味するものでない場合は、あなたの質問を更新してください。 –

2

...これは別のスレッドへのお電話をプッシュし、スレッドが完了したときにあなたが選んだのメソッドを呼び出しますコールバック操作でBeginInvokeメソッドを使用してみてください:

private void btnRequestR2Approval_Click(object sender, EventArgs e) 
{ 
    if (User.IsLogged) 
    { 
     ValidationResults results = new ValidationResults(); 
     results.Show(); 

     Logger log = Logger.Instance(); 
     Logger.NewLogAddedHandler messageDelegate = new Logger.NewLogAddedHandler(results.NewLogMessage); 

     if (!log.IsEventHandlerRegistered()) 
     { 

      log.NewLogAdded += messageDelegate; 
     } 

     ThreadStart operation = new ThreadStart(ValidateAndSubmit); 
     operation.BeginInvoke(MyCallBack, this); 
    } 
    else 
    { 
     MessageBox.Show("Please login"); 
    } 

} 

private static void MyCallBack(IAsyncResult ar) { 
    ((MyForm)ar.AsyncState).Refresh(); 
} 
+0

ar.EndInvokeまたはMyCallbackを呼び出すと、マシンリソースがリークします。 –

+0

このような方法はありません。 – Sergey

+0

実際には(AsyncDelegate)ar.EndInvoke、私の答えを見てください。 –

2

非常に不明瞭な質問、私は仮定します:

  1. ASP.Net WebページではなくWindows Winformsアプリケーションを実行しています。
  2. 長い時間がかかるバックグラウンドの計算をトリガーしたい場合、この間にUIがブロックされないようにします。
  3. バックグラウンドの計算が完了したら、UIに何らかの結果が得られるようにします。
  4. 結果をUIに入力した時点でバックグラウンド計算を終了します。

これが当てはまる場合は、スレッドではなく非同期のデリゲートを使用する必要があります。例:

string SleepAndReturnParam(string param1) 
{ 
    System.Threading.Thread.Sleep(10000); 
    return param1; 
} 

// Declare a delegate matching our async method. 
public delegate string DelegateWithParamReturningString(string param1); 


private void button1_Click(object sender, EventArgs e) 
{ 
    var myDelegate = new DelegateWithParamReturningString(SleepAndReturnParam); 

    // Run delegate in thread pool. 
    myDelegate.BeginInvoke("param1", 
     OnCallBack, // Completion callback 
     this); // value to pass to callback as AsyncState 
} 


private void OnCallBack(IAsyncResult ar) 
{ 
    // first cast IAsyncResult to an AsyncResult object 
    var result = ar as System.Runtime.Remoting.Messaging.AsyncResult; 

    // grab the delegate 
    var myDelegate = result.AsyncDelegate as DelegateWithParamReturningString; 

    // Exit delegate and retrieve return value. 
    string returnValue = myDelegate.EndInvoke(ar); 

    // Declare an anonymous method to avoid having to define 
    // a method just to update a field. 
    MethodInvoker formFieldUpdater = delegate 
    { 
     formTextField.Text = returnValue; 
    }; 

    // Winforms controls must be modified on the thread 
    // they were created in. 
    if (formTextField.InvokeRequired) 
     Invoke(formFieldUpdater); 
    else 
     formFieldUpdater(); 
}