4

あなたが呼び出し元で、メソッドを呼び出したり、コントロールを操作したりするときは、UI スレッド (またはそのコントロールを所有するスレッド) を呼び出す必要があることを私は知っています。

ただし、イベントの 1 つを介してコントロールによってコールバックされる場合、正しいスレッドでコールされていると想定しても安全でしょうか?

コモン コントロールに関する私の経験では、これは常に当てはまりますが、それはおそらく、ほとんどのイベントがユーザー インタラクションの結果であるためです。したがって、Windows メッセージは UI スレッドのメイン メッセージ ループによって処理されます。

最近、ユーザー インタラクション以外の理由でイベントを呼び出す独自のカスタム コントロールの 1 つに問題があり、バックグラウンド スレッドで発生することもあります。あるケースでは、イベントのイベント ハンドラーが別のコントロールを操作しようとしたため、不正なクロススレッド呼び出し例外が生成されました。

イベントハンドラーで呼び出しが必要かどうかを確認することで問題を解決できますが、実際に誰が「過ちを犯している」のか知りたいです。

コントロールのイベントやベスト プラクティスに関する「ルール」を記述しているドキュメントはどこにもありません。誰か知っていますか?または、あなたの意見では、適切なスレッドでサブスクライバーを呼び出すのはコントロールの責任ですか、それともサブスクライバーの責任でチェックする必要がありますか?

編集: 文書化された規則について誰も聞いたことがないようControlですが、消費者を驚かせないために、コントロールの所有スレッドの派生クラスでパブリック イベントを呼び出すことをお勧めします。

4

3 に答える 3

3

メソッドを呼び出したり、コントロールを操作したりする場合は、UI スレッド (またはそのコントロールを所有するスレッド) を呼び出す必要があります。

うーん...議論の余地があります。もちろん、ホストしているスレッド以外のスレッドから UI 要素にアクセスしようとしないでください。ただし、Invoke特にワーカー スレッドからの進捗情報を使用して UI を更新するだけの場合は、UI 要素を更新するための最適なメカニズムとは限りません。勘違いしないでくれ。マーシャリング操作を使用することが完全に理にかなっている時と場所がありますが、多くの場合、UI スレッドを介してそれ自体を更新する必要があるデータをポーリングすることSystem.Windows.Forms.Timerで、通常はよりシンプルで効率的で、同じくらいエレガントなソリューションになります (そうでない場合)。

ただし、イベントの 1 つを介してコントロールによってコールバックされる場合、正しいスレッドでコールされていると想定しても安全でしょうか?

必ずしも。通常、特にControlインスタンスの場合はそうです。Componentただし、インスタンスをフォームにドロップすることもできます。それらの多くは、他のスレッドでイベントを発生させます。十分な反例としてBackgroundWorker.DoWorkとを考えてみましょう。SerialPort.DataReceived

イベントハンドラーで呼び出しが必要かどうかを確認することで問題を解決できますが、実際に誰が「過ちを犯している」のか知りたいです。

責任はあなたにあると言わざるを得ません。コントロールが実際にサブクラス化Controlを行う場合は、すべてのイベントが UI スレッドで発生するように懸命に努力します。そうしないと、(正しいか間違っているかを問わず) UI スレッド上にいると想定している他の開発者を確実に混乱させるでしょう。「コントロール」がサブクラスのみの場合は、おそらく問題ありませんが、コンポーネントの動作を文書化するようにしてください。Component

于 2012-05-05T02:07:09.250 に答える
3

ここで黒魔術が働いていると仮定しないでください。あなたは健全な結果を説明しています。ワーカー スレッドからイベントを発生させる場合、イベント ハンドラーはもちろんそのスレッドでも実行されます。また、そのハンドラーで UI コントロールのプロパティを設定すると、これは合法的な行為ではないことに注意する必要があります。

コントロールによって発生するイベントでも、まったく同じメカニズムが機能しています。これらは、Windows から送信された通知メッセージから動作するため、メッセージ ループをポンピングするスレッドで発生します。ワーカー スレッドでウィンドウを作成するなどの賢明でないことをしない限り、常に Winforms または WPF アプリのメイン スレッド。したがって、これらのイベントは「正しい」スレッドで発生し、コントロールのプロパティの更新は問題になりません。

イベントは、コードを明示的に記述しない限り、あるスレッドから別のスレッドにホップしません。Begin/Invoke()、あなたはすでにそれを知っています。

ab/using InvokeRequired には注意してください。これはアンチパターンです。特定のコードが実行されているスレッドを事前に把握していないのは、不健全です。UI のフリーズを回避するために、長時間実行される dbase クエリをワーカーで実行するとします。したがって、その結果が利用可能になると、結果を表示するために呼び出す必要があることがわかります。InvokeRequired を使用する意味はありませんが、実際に何か問題があることを知らせることができるからです。false を返す場合は、必ず例外をスローしてください。

于 2012-05-05T10:00:12.877 に答える
0

私があなたのコントロールの消費者であり、それを使用してスレッド例外をスローし始めたとしたら、おそらく少しイライラするでしょう:)私は、発生しているイベントをチェックするキャンプにいると思います。サブスクライバーで。

于 2012-05-05T02:00:30.650 に答える