2009-10-27 24 views
6

私は(クロススレッド例外を取得する)私が取り組んでいる大きなアプリケーションでいくつかのスレッド問題があります。特定のコントロールが作成されたスレッド名/ idを見つける方法はありますか?コントロールのオーナースレッドを見つける方法はありますか?

コントロールのコントロールコレクションに新しいコントロールを追加しようとするとエラーが発生します。私は実際に小さな、再現可能なサンプルを作成することはできませんので、私ができる限りそれを説明します。

私はフォーム上に座っているメインコントロールを持っています、それを_mainControlと呼んでください。そのコンストラクタでは、私は別のコントロールのインスタンスをインスタンス化し、

ChildControl _childControl = new ChildControl(); 

のようなものは今_childControlが存在しますが、私はまだ_mainControlsコレクションに追加しないでください。

最終的に_mainControlはコントロールを追加する必要があるというイベント通知を受け取ります。イベントハンドラではthis.InvokeRequired場合、私はチェックして、それがある場合、私は、次のようなものをハンドラを起動します。

AddControlEventHander(...) 
{ 
    if(InvokeRequired) 
    { 
     BeginInvoke(new MethodInvoker(AddControlEventHander); 
     return; 
    } 
    Controls.Add(_childControl); 
} 

例外は常にControls.Add(有効ではありません "クロススレッド動作時にスローされます。コントロール '_item'は、作成されたスレッド以外のスレッドからアクセスされます)。

今、私は理解できないことは、これがどういうことかということです。 _mainControlが作成されたのと同じスレッドで_childControlを作成しました。デバッグ中にスレッドウィンドウを見ると、_childControlが追加されたときと同じようにControl.Addを呼び出すと、現在のスレッド名/ IDが同じになります。しかし、私を最も混乱させるものは、_mainControlからの以下の呼び出しです。

InvokeReuqired == false; 
_childControl.InvokeRequired == false; 
_childControl._item.InvokeRequired == true; //I made _item public just to try this and it returns true! 

これはどのように可能ですか? _childControlは、その子が別のスレッドで何らかの形で作成されている間に1つのスレッドで作成することは可能ですか? _childControlのすべての子は、通常行われるように、初期化中に作成されます。

何が起こっているのかについてのヒントや提案がありましたら、お知らせください。

ありがとうございました。

編集:誰もが興味を持っている

場合は、私が起こっていたことが分かりました。 1つのスレッドでコントロールを作成する方法と、同じスレッドでInitializeComponentがすべて実行されたにもかかわらず、別のスレッドで作成された子が好きです。そこで、チャールズが以下に示唆したのと同様のコードを使って、子供が作成されたスレッドを見つけました。私がそれを知ったら、少なくとも、どのスレッドに集中すべきかを知っていました。次に、子コントロールのOnHandleCreatedイベントを壊して問題を発見しました。

私が知らなかったことは、コントロールが初めて作成されたときにコントロールが表示されたときにコントロールのハンドルが作成されることでした。したがって、コントロールを所有していないスレッドは、可視性をtrueに設定しようとしていました。だから私はInvokeRequiredとそれがトリックを行うだろうと思ったかどうかを確認するためのチェックを追加しました。しかし、私が実際には期待していなかったことは、まだ作成されていない場合、InvokeRequiredを呼び出すとコントロールのハンドルが作成されるということです!これにより、実際には間違ったスレッドでコントロールが作成され、常にInvokeRequiredに対してfalseが返されます。コントロールのHandleプロパティに触れ、InvokeRequiredが呼び出される前にコントロールが作成されるようにして、この問題を回避しました。ヘルプみんなのため

感謝:)

+0

ヒントをお寄せいただきありがとうございます。同様に無害な 'if(control.Handle!= null)...'が実際にそのスレッドのコントロールを作成することも発見しました! –

+0

ここに私の答えを見なさいhttp://stackoverflow.com/questions/8331144/ensuring-that-c​​hild-controls-are-created-in-main-ui-thread/17054689#17054689 –

答えて

3

これを試して、制御のための所有者のスレッドを取得するには:

private Thread GetControlOwnerThread(Control ctrl) 
{ 
    if (ctrl.InvokeRequired) 
     ctrl.BeginInvoke(
      new Action<Control>(GetControlOwnerThread), 
      new object[] {ctrl}); 
    else 
     return System.Threading.Thread.CurrentThread; 
} 

は、子コントロールは、親(コンテナコントロール)とは別のスレッドでもできますか?はい、すべてのスレッドは、コントロールが構築されたときに実行されていたかどうかによって決まります(new'ed)

いつもInvokeRequiredをチェックする必要があります。 ..それぞれの子コントロールごとに個別にInvokeRequiredをチェックする必要があるかどうかは、すべてのコントロールが同じスレッド上に作成されたかどうかにかかっています。同じ初期化ルーチンでフォームが作成されたときにすべてのコントロールが作成された場合、それらがすべて同じスレッド上に作成されたとみなすことはおそらく安全です。

+0

Hmm。それで、InvokeRequiredがコントロールに必要かどうかを確認しようとすると、どのようなチェックが必要ですか?コントロールとそのすべての子に対して、常にInvokeRequiredをチェックする必要がありますか? – Flack

+0

はい、あなたは常にInvokeRequiredをチェックする必要があります...あなたがコーディングするメソッドにどのスレッドが呼び出されているのかわからないので...各子コントロールごとに個別にInvokeRequiredをチェックする必要があるかどうかは、コントロールは同じスレッド上に作成されたかどうかはわかりません。フォームが作成されたときに、同じ初期化ルーチンですべてのコントロールが作成された場合、それらがすべて同じスレッド上に作成されたと想定するのはおそらく安全です。 –

+0

それは私にとってとても奇妙に見えるものです。私が知ることから、_childControlとその子はすべて同じスレッド上に作成されたように見えます。また、_childControlsの子が何らかの形で別のスレッドで作成された場合、_mainControlのControls.Addを呼び出す方法がわかりません。なぜなら、_childControlハンドルがクロススレッドのために作成されていると失敗するからです。 _childControlまたはその子のために失敗しました。私はこれがどのように可能であるかはわかりません。私はそれを再訪し、いくつかのリファクタリングを行います。多分それは離れて行くでしょう:) – Flack

関連する問題