2010-12-02 10 views
1

私は、マルチスレッドアプリケーションでGUIを使用する方法について少し混乱しています。スレッド、イベント、GUI

UIスレッドと呼ばれるものがあります。私が想定しているのは、アプリケーションの起動時の主な実行スレッドです。

他の(UI以外の)スレッドでUIの処理を行うことは非常に悪い考えですが(私は100%ではありませんが)これも聞いています。

別スレッドを作成してMyForm myForm = new MyForm(); myForm.ShowDialog();に電話したい場合は、それを「安全」にするためにどのような変更が必要ですか?

また、私はイベントが別のスレッドでスピンアウトされたと言う人もいました。 (私はこれを信じているとは確信していませんが)そうであれば、私は混乱しています。私はイベントでダイアログ(すなわちmyForm.ShowDialog()を開くことができ、本当に恐ろしい何も起こりません。(イベントデリゲートをInvokeBeginInvokeで呼び出された場合、多分これが依存?)

+0

すべての偉大な答えをありがとう!私は「正しい」答えとして複数を選択することができたらいいと思う。 – Vaccano

答えて

3

をここであなたを助けるかもしれない情報のいくつかのビットがありますあなたがUI以外のスレッドでUIを使って作業していると言っていることは、悪い考えではなく、例外が発生します。つまり、メインスレッドでフォームを作成し、いくつかの処理をして、そのバックグラウンドスレッドのフォームを更新したい場合、例外がスローされます。ただし、バックグラウンドスレッドでフォームを作成する場所では、あなたはOKです。 同じUIの中にあなたがたに触れている限り、

イベントの場合、イベントハンドラは、発生した同じスレッドで実行されます。つまり、イベントを発生させる別のスレッドで何らかの作業を開始するフォームを1つのスレッドに作成している場合は、そのフォームのスレッドでこのイベントにフックすると、UIに直接触れないように注意する必要があります。それらのイベントハンドラがバックグラウンドスレッドで呼び出されているためです。

最後に、バックグラウンドスレッドからUIを正しく操作するには、Invokeを呼び出し、必要なUI作業を行うデリゲートを渡します。 HTH

3

WinFormsではUIスレッドでUIを呼び出す必要がありますが、現在どのスレッドがUIコントロールのInvokeRequiredを取得しているかを常に確認できます。

void ApplyUiChanges() 
{ 
    if(this.InvokeRequired) 
    { 
     this.Invoke(new Action(ApplyUiChanges)); 
     return; 
    } 

    // UI stuff here... 
} 

WPF techinicは同様です。しかし、その代わりにInvokeRequiredを使用してのあなたは

void ApplyUiChanges() 
{ 
    if (!dispatcherObject.CheckAccess()) 
    {  
     dispatcherObject.Dispatcher.Invoke(DispatcherPriority.Send, new Action(ApplyUiChanges)); 
     return; 
    } 
    // UI stuff here... 
} 

(すべてのUI-コントロールはそれから派生)DispatcherObjectCheckAccess()に依頼する必要があります。また、あなたは便利であるかもしれない、Async CTPを見てみることができます。しかしそれはまだCTPだけで、リリースではない。

UIスレッド通信を処理する別の方法は、PostSharpを使用することです。 GuiThreadAttributeを書いてください(またはコピー&ペースト)。その後、あなたは、このようなセマンティクスを使用することができます:WinFormsのアプリケーションで

[GuiThread] 
void ApplyUiChanges() 
{ 
    // UI stuff here... 
} 
2

UIスレッドでのみ、単一のスレッドがあります。長い操作でこのスレッドをブロックしないようにして、UIが常に応答するようにします。また、UIスレッド以外のスレッドからUI要素を更新しないでください。
UIから長時間の操作を実行する場合は、常にBackgroundWorkerを使用します。BackgroundWorkerの主な利点は、進行状況を報告し、ProgressChangedとRunWorkerCompletedで完了したことを報告できることです。これらの2つのイベントはUIスレッドで発生するため、InvokeRequiredとInvokeを使用する必要はなく、すべてのUI要素を安全に更新できます。

3

私が経験したことから、「UIスレッド」は誤った名前です。アプリケーションのすべてのUIを処理する単一のスレッドはありません。物事を単純にするためには、あるスレッドにUIを持たせることは一般的には良い考えですが、別のスレッドを作成してそのスレッドに新しいコントロールを作成してユーザーに表示することを止めるものはありません。重要なのは、制御プロパティが上に作成されたスレッド上でのみに変更されていることです。別の人に言われているように、Control.InvokeRequiredプロパティを見て、そのスレッドに現在いるかどうかを知ることができます。

新しいフォームを実行したいスレッドではなく、必要なスレッドで作成されたコントロールのコンテキスト上に贅沢を感じることができない場合は、あなたはそれが欲しいスレッドのSystem.Threading.SynchronizationContextへの参照を取得しなければなりません(私は通常、System.Threading.SynchronizationContext.Currentの参照をメインスレッドから静的変数に格納することでこれを実現しますが、これは少なくとも1つのコントロールがスレッド上に作成された後にのみ実行できます)。このオブジェクトを使用すると、ホームスレッドでデリゲートを実行できます。

WCFサービスをホストしているWindowsアプリケーションでこれを1回実行する必要がありました。このサービスからUIを起動する必要がありましたが、残りのUIと同じスレッドで使用する必要がありました。

HTH、 ブライアン

+0

+1は誤った名前のため、本当に混乱しています –

関連する問題