Windows フォーム内のコントロールは、特定のスレッドにバインドされているため、スレッド セーフではありません。したがって、異なるスレッドからコントロールのメソッドを呼び出す場合は、コントロールの invoke メソッドを使用して、適切なスレッドへの呼び出しをマーシャリングする必要があります。このプロパティを使用すると、invoke メソッドを呼び出す必要があるかどうかを確認できるため、どのスレッドがコントロールを所有しているかわからない場合に役立ちます。
メモ : |
|---|
コントロールのハンドルが既に作成されている場合、InvokeRequired プロパティ以外に、呼び出しに対してスレッド セーフである 4 つのメソッド Invoke、BeginInvoke、EndInvoke、および CreateGraphics がコントロールにあります。コントロールのハンドルがバックグラウンド スレッドで作成される前に CreateGraphics を呼び出すと、無効なスレッド間の呼び出しが発生する可能性があります。その他のすべてのメソッドの呼び出しについては、異なるスレッドから呼び出すときは、これらの invoke メソッドの 1 つを使用する必要があります。 |
コントロールのハンドルがまだ存在しない場合、InvokeRequired メソッドはコントロールの親チェインを検索し、ウィンドウ ハンドルを持つコントロールまたはフォームを見つけます。適切なハンドルが見つからない場合、InvokeRequired メソッドは false を返します。
つまり、Invoke が必須ではない (同じスレッドで呼び出しが行われる) 場合、またはコントロールが異なるスレッドで作成されるが、コントロールのハンドルがまだ作成されていない場合、InvokeRequired は false を返す可能性があります。
コントロールのハンドルがまだ作成されていない場合、コントロールでプロパティ、メソッド、またはイベントを呼び出さないでください。これにより、コントロールのハンドルがバックグラウンド スレッドで作成され、メッセージ ポンプのないスレッド上でコントロールが分離されて、アプリケーションが不安定になる可能性があります。
バックグラウンド スレッドで InvokeRequired が false を返す場合、IsHandleCreated の値を確認する方法でも、この状態が発生するのを回避できます。コントロール ハンドルがまだ作成されていない場合は、コントロール ハンドルが作成されるまで待機してから、Invoke または BeginInvoke を呼び出す必要があります。通常、これが発生するのは、アプリケーションのメイン フォームが表示される前または Application.Run が呼び出される前に、メイン フォームのコンストラクタでバックグラウンド スレッドが作成される場合です (たとえば、Application.Run(new MainForm()))。
1 つの解決策としては、フォームのハンドルが作成されるまで待機してから、バックグラウンド スレッドを開始します。Handle プロパティを呼び出してハンドルを強制的に作成するか、Load イベントがバックグラウンド プロセスを開始するまで待機します。
より優れた解決策としては、スレッド間のマーシャリングではなく、SynchronizationContext によって返される SynchronizationContext を使用します。
メモ : |
|---|
メッセージを処理するスレッドが既に非アクティブになっていた場合は、例外がスローされます。 |
マルチスレッド処理された Windows フォーム コントロールの詳細については、「方法 : バックグラウンド スレッドを使用してファイルを検索する」および「方法 : Windows フォーム コントロールのスレッド セーフな呼び出しを行う」を参照してください。