2011-08-24 5 views
15

を作成されるまで呼び出しまたはBeginInvokeをコントロールで呼び出すことができない私は、次の例外がスローされ得る:ウィンドウハンドルが

ウィンドウハンドルが作成されるまで呼び出しまたはBeginInvokeをコントロール上で呼び出すことはできません。

これは私のコードです:

if (InvokeRequired) 
{ 
    BeginInvoke(new UpdateTextFieldDelegate(WriteToForm), finished, numCount); 
} 
else 
    Invoke(new UpdateTextFieldDelegate(WriteToForm), finished, numCount); 

私はこのサイトには、このトピックに関するページを見つけましたが、私が間違っているかわかりません。

+1

あり、それはあなたのフォームが完全に初期化/作成される前に、あなたがイベントを起動しているように聞こえる、または別のスレッド上でいくつかの時点でどこそれはshouldnそうです。 –

+1

タイマー(System.TimersまたはSystem.Threading)を実行している場合は、完全に構築されていないか、または処分されていないフォームでこのコードが実行されているかどうかを確認します。 –

+0

このコードはどこにありますか、どのメソッドまたはイベントハンドラですか?答えのために – Kev

答えて

47

InvokeとBeginInvokeの違いは、前者が同期(完了を待つ)で、後者が非同期(一種のfire-and-forget)であることです。しかし、どちらも、UIメッセージループにメッセージを投稿することによって動作し、そのメッセージに到達したときにデリゲートが実行されます。

InvokeRequiredプロパティは、呼び出しをすべて呼び出す必要があるか、または同期スレッドまたは非同期呼び出しを必要とするかどうかではなく、正しいスレッドに既に存在するかどうかを判断します。 InvokeRequiredがfalseの場合は、UIスレッド上で(理論的には)すでに実行されています。単純に同期アクションを直接実行することもできます(非同期で非同期に起動する必要がある場合はBeginInvokeを使用することもできます)。これは、InvokeRequiredがfalseの場合はInvokeを使用できないことを意味します。これは、現在のスレッドのメッセージループを継続する手段がないためです。上記のコードには大きな問題がありますが、必ずしもあなたが報告しているエラーではありません。 は、いずれの場合でもBeginInvokeを実際に使用します。再帰呼び出しを監視する場合は、以下同様です。

ただし、ウィンドウハンドルなしではどちらも使用できません。フォーム/コントロールがインスタンス化されていても初期化されていない場合(つまり、最初に表示される前)、まだハンドルがない可能性があります。また、フォームが閉じられた後など、Dispose()によってハンドルがクリアされます。いずれの場合も、ハンドルなしでは呼び出すことができないため、InvokeRequiredはfalseを返します。 IsDisposedをチェックすることができます。また、ハンドルが存在するかどうかを具体的にテストするプロパティIsHandleCreatedもあります。通常、IsDisposedがtrueの場合(またはIsHandleCreatedがfalseの場合)、アクションを単純に削除するなどの特殊なケースにパントします。

だから、あなたが望むのコードは、おそらくもっとようである:あなたがコントロールを表示する前に別のスレッドからコントロールを使用するつもりかやっている場合は

if (IsHandleCreated) 
{ 
    // Always synchronous. (But you must watch out for cross-threading deadlocks!) 
    if (InvokeRequired) 
     Invoke(new UpdateTextFieldDelegate(WriteToForm), finished, numCount); 
    else 
     WriteToForm(finished, numCount); // Call the method (or delegate) directly. 

    // Execution continues from here only once WriteToForm has completed and returned. 
} 
else 
{ 
    // Handle the error case, or do nothing. 
} 
+0

thx。 – senzacionale

+0

これは、メインのUIスレッドでメソッドを呼び出す非同期タスクにも便利ですが、フォームは呼び出しが呼び出される前に破棄されます。 –

7

これは通常、フォームが適切に初期化される前に、外部ソース(NetworkStreamなど)がデータをフォームにプッシュするマルチスレッドのシナリオで発生します。

メッセージは、フォームが破棄された後にも表示されます。

IsHandleCreatedをチェックすると、フォームがすでに作成されているかどうかを確認できますが、アプリケーションが終了している間にフォームを更新しようとすると、Invokeステートメントが例外をスローする可能性があるため、

2

if (IsHandleCreated) 
{ 
    // Always asynchronous, even on the UI thread already. (Don't let it loop back here!) 
    BeginInvoke(new UpdateTextFieldDelegate(WriteToForm), finished, numCount); 
    return; // Fired-off asynchronously; let the current thread continue. 

    // WriteToForm will be called on the UI thread at some point in the near future. 
} 
else 
{ 
    // Handle the error case, or do nothing. 
} 

それともコントロールを持つ他のものは、コンストラクタ内でそのハンドルの作成を強制することを検討してください。これはCreateHandle機能を使用して行われます。 "コントローラ"ロジックがWinFormにないマルチスレッドプロジェクトでは、この関数はこれらの種類のエラーを回避する手段となります。

1

フォームのコンストラクタでこれを呼び出すことがあります。その時点で、基になるシステムウィンドウハンドルはまだ存在しません。

5

ここは私の答えです

テキストボックスに "Hello World"と書いてみましょう。 次に、 "Ishandlecreated"を使用すると、ハンドラがまだ作成されていないと操作は行われません。したがって、まだ作成されていない場合は、CreateHandlerを強制する必要があります。ここで

問題の詳細を知らなくても、私のコード

if (!IsHandleCreated) 
    this.CreateControl(); 

this.Invoke((MethodInvoker)delegate 
{ 
    cmbEmail.Text = null; 

}); 
関連する問題