2

Windows svc (別のプロセス) を実行し、同時に UI を更新するコードがあります。呼び出しはBeginInvoke、次のように使用します。

Install.BeginInvoke((MethodInvoker) delegate { Install.Enabled = false; });

これはDoWorkイベント ハンドラにあります。ただし、UI はまだフリーズします。どこかに電話する必要がありますApplication.DoEventsか (必要な場合、どこに?)? 凍結を解消するにはどうすればよいですか?

ボタンクリックで、私は持っています:

GetPrinterDto(DirectoriesTreeView.SelectedNode.Text);

InstallBackgoundWorker.RunWorkerAsync();

InstallBackgroundWorkerUIなどを更新するコードを実行するだけです。

私がやろうとしているのは、WCF サーバー (Windows サービスでホストされている - これは問題ありません) を呼び出すことですが、それが機能していない間に、プログレス バーとラベルを任意の値で非同期に更新します。ツリー ノードを選択すると、選択したツリー ノードのイベント ハンドラーが起動され、速度が低下する場合があります。これを独自のバックグラウンドワーカーに入れてみます。

4

2 に答える 2

4

確かに、メソッドでUI(呼び出しが行っていること)を更新するための呼び出しを行うことはできますが、そうしないと、クラスは実際には必要ありません。BeginInvokeDoWorkBackgroundWorker

むしろ、イベントを発生させるReportProgressメソッドを呼び出すことになります。ProgressChanged

ProgressChangedを呼び出すのは、イベントのイベントハンドラーですInstall.Enabled = false

于 2011-05-09T16:41:42.877 に答える
1

この問題は、 の使用とは直接関係ありませんBeginInvoke。それはおそらく、それがどれだけ呼び出されているかに関係しています。ReportProgressイベントと組み合わせて使用​​することもできますが、すべての呼び出しをProgressChangedに置き換えると、 /が使用しているのと同じメカニズムを使用して UI スレッドでイベント ハンドラーを自動的にマーシャリングするため、同様の問題が発生する可能性があります。手っ取り早い解決策は、UI を更新しようとする頻度を減らすことだと思います。BeginInvokeReportProgressBackgroundWorkerBeginInvokeInvoke

個人的BeginInvokeには、ワーカー スレッドの進行状況で UI を更新するために を使用するのは使いすぎだと思います。そして同じ点で、クラスはこの次善の方法も促進します。通常は、ワーカー スレッドが更新情報を共有データ構造に定期的に発行し、UI スレッドが独自のスケジュールで (通常は を使用してポーリングして) 取得できるようにすることをお勧めします。これにはいくつかの利点があります。BackgroundWorkerTimer

  • これにより、UI とワーカー スレッド間の密結合が解消されControl.Invoke\Control.BeginInvokeます。
  • いずれにせよ、それが属するべきUIスレッドにUIスレッドを更新する責任を負わせます。
  • UI スレッドは、更新をいつ、どのくらいの頻度で行うべきかを指示します。
  • ワーカー スレッドによって開始されるマーシャリング手法の場合のように、UI メッセージ ポンプがオーバーランするリスクはありません。
  • ワーカー スレッドは、次のステップに進む前に、更新が実行されたという確認応答を待つ必要はありません (つまり、UI スレッドとワーカー スレッドの両方でより多くのスループットが得られます)。

残念ながら、BackgroundWorkerこの代替アプローチを使用するために必要なメカニズムが欠けています。ただし、あまり頻繁に呼び出さない限り、問題なく使用できます。ReportProgress

于 2011-05-09T18:07:10.833 に答える