[解決済み] ウィンドウハンドルが作成されるまで、コントロールに対してInvokeまたはBeginInvokeを呼び出すことはできません。
質問
次のような SafeInvoke Control 拡張メソッドを持っています。 Greg D がここで説明している (IsHandleCreated チェックを除いたもの) に似ています。
から呼び出しています。
System.Windows.Forms.Form
を以下のように呼び出しています。
public void Show(string text) {
label.SafeInvoke(()=>label.Text = text);
this.Show();
this.Refresh();
}
時々(この呼び出しは様々なスレッドから来る可能性があります)、これは次のようなエラーになります。
System.InvalidOperationException
が発生
Message
= "ウィンドウハンドルが作成されるまで、InvokeまたはBeginInvokeはコントロール上で呼び出すことができません。
Source
= "System.Windows.Forms".System.Windows.Forms"。StackTrace: at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous) at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args) at System.Windows.Forms.Control.Invoke(Delegate method) at DriverInterface2.UI.WinForms.Dialogs.FormExtensions.SafeInvoke[T](T control, Action`1 action) in C:\code\DriverInterface2\DriverInterface2.UI.WinForms\Dialogs\FormExtensions.cs:line 16
何が起こっていて、どうすれば直るのでしょうか? 一度うまくいって、次に失敗することがあるので、フォーム作成の問題でないことは十分承知していますが、問題は何でしょうか?
PS. 私は本当に本当にWinFormsでひどいです、誰かモデル全体とそれを使用する方法を説明する良い記事のシリーズを知っていますか?
どのように解決するのですか?
間違ったスレッドでコントロールを作成している可能性があります。 次のように考えてください。 MSDN のドキュメント :
つまり、InvokeRequiredは が false を返すということです。 (呼び出しは同じスレッドで発生します)。 あるいは コントロールが別のスレッドで作成された場合 コントロールが別のスレッドで作成されたが、そのコントロールの ハンドルがまだ作成されていない場合。
コントロールのハンドル がまだ作成されていない場合は コントロールのプロパティ、メソッド、イベントを単純に呼び出すことはできません。 またはイベントを呼び出すべきではありません。これは コントロールのハンドルがバックグラウンドスレッドで作成され をバックグラウンドスレッドで作成することになります。 メッセージポンプのないスレッドでコントロールを孤立させ メッセージ・ポンプのないスレッドでコントロールが孤立し アプリケーションを不安定にします。
このケースを防ぐには の値もチェックすることで、このケースを防ぐことができます。 をチェックすることで、このケースを防ぐことができます。 が false を返したとき、バックグラウンドスレッドで コントロールハンドルがまだ作成されていない場合 コントロール・ハンドルがまだ作成されていない場合は、作成されるのを待ってから を呼び出す前に、それが作成されるまで待たなければならない。 BeginInvokeを呼び出す前に、作成されるまで待つ必要があります。一般的に、これは バックグラウンドスレッドが主フォームのコンストラクタで作成された場合 のコンストラクタでバックグラウンドスレッドが作成される場合のみです。 のコンストラクタでバックグラウンド・スレッドが作成された場合のみ発生します (例 Application.Run(new MainForm()) のように)。 フォームが表示される前、あるいは Application.Run が呼び出される前に、アプリケーションのプライマリフォームのコンストラクタでバックグラウンドスレッドが作成される場合のみです。
これがあなたにとって何を意味するのか見てみましょう。 (これは、SafeInvokeの実装も見ていれば、推論しやすいでしょう)
に対するチェックを除いて、あなたの実装が参照されたものと同一であると仮定します。 IsHandleCreated に対するチェックを除いて、参照されたものと同じであると仮定して、ロジックを追ってみましょう。
public static void SafeInvoke(this Control uiElement, Action updater, bool forceSynchronous)
{
if (uiElement == null)
{
throw new ArgumentNullException("uiElement");
}
if (uiElement.InvokeRequired)
{
if (forceSynchronous)
{
uiElement.Invoke((Action)delegate { SafeInvoke(uiElement, updater, forceSynchronous); });
}
else
{
uiElement.BeginInvoke((Action)delegate { SafeInvoke(uiElement, updater, forceSynchronous); });
}
}
else
{
if (uiElement.IsDisposed)
{
throw new ObjectDisposedException("Control is already disposed.");
}
updater();
}
}
を呼び出す場合を考えてみましょう。
SafeInvoke
を非GUIスレッドから呼び出している場合を考えてみましょう。
uiElement
はnullではないので、チェックするのは
uiElement.InvokeRequired
. MSDN のドキュメントによると (太字)
InvokeRequired
は
false
なぜなら、別のスレッドで作成されたにもかかわらず、ハンドルが作成されていないからです! これは私たちを
else
をチェックすることになります。
IsDisposed
をチェックするか、すぐに送信されたアクションの呼び出しに進みます...
バックグラウンドスレッドから
!
この時点では、2 番目の段落で述べたように、そのハンドルはメッセージ ポンプを持たないスレッドで作成されているため、そのコントロールに関するすべての賭けが外されています。 おそらくこれは、あなたが遭遇しているケースです。
関連
-
[解決済み】クロススレッド操作が有効でない。作成されたスレッド以外のスレッドからアクセスされたコントロール
-
[解決済み] Visual Studio 2012の「タブ順序の割り当て」ダイアログはどこにありますか?
-
[解決済み】node.jsでコールバックが呼ばれるまで関数を待機させる方法
-
[解決済み】Invoke()とBeginInvoke()の違いは何ですか?)
-
[解決済み] WindowsフォームのUIデザインパターン(WPFのMVVMのようなもの)
-
[解決済み] Datagridview - 最初のカラムの前の部分を削除する
-
[解決済み] 「Subversionへのコミット後、「プロジェクトの依存関係を更新できません。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン