2012-05-08 5 views
0

APIを介して私にプッシュされた株価情報を持つプログラムがあります。また、このプログラムは、XAMLで作成されたフロントエンドを備えています。このフロントエンドは、このプログラムの実行中にフリーズします(つまり、APIが送信している情報を処理しています)。私はDispatcher.InvokeやBackgroundWorkerを使って試してみましたが、スレッディングをたくさん読んだことがありますが、アンフリーズすることはできません。多分私は何か間違っているだけかもしれません。関連するコードをここに添付しました。誰かが助けることを望んでいた。C#XAML GUIがAPI関数のためにフリーズする

private void QuoteUpdate(QuoteInfo info) 
    { 
     BackgroundWorker bwQuoteUpdate = new BackgroundWorker(); 
     bwQuoteUpdate = new BackgroundWorker(); 
     bwQuoteUpdate.WorkerSupportsCancellation = true; 

     bwQuoteUpdate.DoWork += bwQuoteUpdate_DoWork;    
     bwQuoteUpdate.RunWorkerAsync(info);   
    } 

    private void bwQuoteUpdate_DoWork(object sender, DoWorkEventArgs e) 
    { 
     try 
     { 
      Dispatcher.Invoke(DispatcherPriority.Normal, new ThreadStart(() => 
      { 
       QuoteInfo info = e.Argument as QuoteInfo; 
       //logical functions and work are here 

      })); 
     } 
     catch (Exception ex) 
     { 
      System.Windows.Forms.MessageBox.Show("Error in QuoteUpdate: " + ex.Message, "Exception Thrown"); 
     } 

    }   
+0

を試してみてください? – Tejs

+0

はい、.NET 4にあります – jeev7882

答えて

1

あなたがバックグラウンドスレッドであなたの長時間実行中のタスクを実行することを意図してBackgroundWorkerを作成しているが、あなたはまだ戻って、UIスレッドへのすべての処理を派遣しています。あなたがする必要がどのような

private void bwQuoteUpdate_DoWork(object sender, DoWorkEventArgs e) 
{ 
    // Code here runs on background thread. 

    Dispatcher.Invoke(DispatcherPriority.Normal, new ThreadStart(() => 
    { 
     // Code here runs on UI thread. 
    })); 
} 

最初は、バックグラウンドスレッドで、あなたの計算を実行しているが、任意のUIコンポーネントを更新しません。むしろ、すべての結果をローカル変数に格納します。それが完了したら、Dispatcher.Invokeを使用してコントロールをUIスレッドに戻し、ローカル変数に格納された結果を使用してUIを更新します。例えば

private void bwQuoteUpdate_DoWork(object sender, DoWorkEventArgs e) 
{ 
    // Code here runs on background thread. 
    QuoteInfo info = e.Argument as QuoteInfo; 
    string result = PerformLongRunningProcessing(info); 

    Dispatcher.Invoke(DispatcherPriority.Normal, new ThreadStart(() => 
    { 
     // Code here runs on UI thread. 
     this.resultTextBox.Text = result; 
    })); 
} 
+0

優秀!この返答をありがとうダグラス。それは完全に意味をなさない。 Dispatcher.InvokeがすべてをUIスレッドに戻していたことに気付かなかった。私は関数からUIの更新を分けるためにいくつかの作業をしなければならないでしょうが、それは論理的な解決策であるようです。 – jeev7882

+0

はい、あなたは、UIの更新を行う必要がある場合はいつでも、 'Dispatcher.Invoke'呼び出しをあなたの関数に散らばらないようにしたい場合を除いて、その分離を実行する必要があります。 'Dispatcher.Invoke'を使うもう一つの方法は' BackgroundWorker'インスタンスの 'RunWorkerCompleted'イベントを購読することです。これはUIスレッド上でいつも起きるでしょう。(実際には良いデザインではありません。 'BackgroundWorker'がUIスレッドでも初期化されていると仮定します)。 – Douglas

+0

Dispatcher.Invokeを関数内で使用するのが良いデザインではないことを簡単に説明できますか?それはより遅く、そして/またはそれほど堅牢ではありませんか? – jeev7882

1

はい、あなたが何か間違ったことをやっています。計算はスレッドでのみ行う必要があります。のUI変更はDispatcher.Invokeで行う必要があります。

INotifyPropertyChangeでデータバインディングを使用する場合は、Dispatcher.Invokeを完全に削除してください。UIスレッドへの変更のマーシャリングは自動で行われるためです。

+1

最後の部分は本当ですか?依存関係プロパティへのデータバインディングを行っている場合は、バックグラウンドスレッドから依存関係プロパティを更新しようとすると例外が発生します。 – Douglas

+0

私はINotifyPropertyChangedについて話しています。そして、狂っている人だけが(ビュー)モデルでDependencyPropertyを使用します。これが理由の一つです。 – Euphoric

+0

あなたは間違っています。 UIコンポーネントが、バックグラウンドスレッドから発生した 'PropertyChanged'イベントを持つプロパティにバインドすると、' InvalidOperationException'( "クロススレッドオペレーションが検出されました")が返されます。 – Douglas

0

は、.NET 4を使用してい

Dispatcher.BeginInvoke(...) 
+0

ダグラスはすでに述べたように、これは競争条件に問題を引き起こす可能性があります。私が扱っている出来事の頻度によって、これは実装するには大きな苦痛になるでしょう。 – jeev7882

関連する問題