C# でのクロススレッド例外の回避: UI コントロールの安全な更新
問題: C# アプリケーションでは、メイン UI スレッド以外のスレッドから UI コントロールを更新するときに、「クロススレッド操作が無効です」という例外が頻繁に発生します。これは通常、マイクロコントローラーの UART ポートなどの外部ソースからのデータを別のスレッドで処理するときに発生します。
シナリオ: マイクロコントローラーが UART 経由で温度データを送信していると想像してください。 C# アプリケーションはこのデータをバックグラウンド スレッドで受信しますが、温度値を使用して TextBox
を直接更新しようとすると例外がスローされます。
根本原因: UI コントロールは、作成されたスレッドにバインドされています。 別のスレッドからアクセスすると、このルールに違反します。
解決策: ディスパッチャーの活用
これを解決する鍵は、UI の更新が正しいスレッドで行われることを保証するメカニズムであるディスパッチャーを使用することです。 これには、シンプルだが効果的なパターンが含まれます:
デリゲートの作成: UI 更新操作をカプセル化するデリゲートを定義します:
<code class="language-csharp">delegate void SetTextCallback(string text);</code>
Update メソッドを実装します: このメソッドは、現在のスレッドが UI スレッドであるかどうかを確認します。そうでない場合は、Invoke
を使用して更新を UI スレッドにマーシャリングします:
<code class="language-csharp">private void SetText(string text) { if (this.textBox1.InvokeRequired) { SetTextCallback d = new SetTextCallback(SetText); this.Invoke(d, new object[] { text }); } else { this.textBox1.Text = text; } }</code>
バックグラウンド スレッドからの更新: serialPort1_DataReceived
イベント ハンドラー (または同等のもの) で、データの受信後に SetText
メソッドを呼び出します:
<code class="language-csharp">private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { string receivedData = serialPort1.ReadExisting(); SetText(receivedData); }</code>
このアプローチにより、すべての UI 更新がメイン UI スレッドで安全に実行され、クロススレッド例外が防止されます。 InvokeRequired
チェックは、更新がすでに正しいスレッド上にある状況を効率的に処理し、不要なオーバーヘッドを回避します。
以上がクロススレッド例外を回避するために、C# の別のスレッドから UI コントロールを安全に更新する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。