- - PR -
Control.ControlCollection.Add メソッドについて
投稿者 | 投稿内容 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2006-04-19 15:55
いつもお世話になります。
さかもとと申します。 VS2005(VB2005:Winアプリ) framework2.0 フォームA上に配置されてグループボックス、 さらにそのグループボックス内に配置された コントロールを別のグループボックスに 追加する方法を検討しています。 現在テストとして、グループボックス上に 9つのコントロールを配置しています。
上記のように記述して、myGpbに9つのコントロール がセットされるかと思いましたが、実際には 5つのコントロールしかセットされません。 それぞれのグループボックス内のコントロールの 数をループ内で見たところ GroupBoxA.Controls.Count(左) - myGpb.Controls.Count(右) 8-1 7-2 6-3 5-4 4-5 と左が4になった時点でループを抜けてしまいます。 Controls.Addメソッドはドキュメントによると 「Control が既に他のコントロールの子コントロールである場合は、 別のコントロールに追加される前にそのコントロールから削除されます。」 とのことなので最終的にGroupBoxAのコントロールの数が 0になるまで繰り返されるのかと思っていましたが、 コントロールの数を増減させて試したところ、 上記の例でいうと(左)の数が(右)の数より少なく なった時点でループを抜けているようです。 記述方法でおかしなところがあればご指摘頂ければと 思います。 宜しくお願いいたします。 | ||||||||||||
|
投稿日時: 2006-04-19 16:14
GroupBoxA.Controlsを列挙している最中に数が変動するというのを気持ち悪く感じませんか? #って、それが原因だよなぁ?。。。ちょっと不安
でどうでしょうか。 [ メッセージ編集済み 編集者: まどか 編集日時 2006-04-19 16:16 ] | ||||||||||||
|
投稿日時: 2006-04-19 16:27
多分そうですね。
というより、半分になった時点で、という方が正しいでしょうね。 という事で、For Each で回しているコレクションを For Each 内で削除すると意図しない動きになってしまいます。 #でも、明示的に削除のコードがあるわけじゃあないから、難しいですね、コレ。 [ メッセージ編集済み 編集者: 囚人 編集日時 2006-04-19 16:29 ] | ||||||||||||
|
投稿日時: 2006-04-19 16:29
さかもとです。
まどか様、ご返答ありがとうございます。
でうまくいきました。 ただ、 >#って、それが原因だよなぁ?。。。ちょっと不安 おっしゃるように、それが原因かどうかが分かりません・・・。
この場合はもちろんうまくいきますが、最初に私が試した コントロールの列挙中での処理の場合だけうまくいかない ような・・・。 .Netframework1.1で最初の例を試したところ (以下は最初の書き込みの(左)-(右)です) 8-1 7-2 6-3 5-4 4-5 4-5 4-5 4-5 4-5 と9回ループした後に抜けています。 ただし、コントロールの数は4つ5つのままで2.0での結果と 変わりませんでした。 方法としてはやはりよろしくないのでしょうか・・・。 | ||||||||||||
|
投稿日時: 2006-04-19 16:41
囚人様
ご返答ありがとうございます。 >、For Each で回しているコレクションを For Each 内で削除すると意図しない動きになってしまいます。 なるほど、そういうことなんですね・・・。 理論上は綺麗に行くはずじゃないかと思い込んでいましたが、 言われてみればおっしゃる通りかと・・・。 まどか様のコードで実装させて頂きます。 勉強になりました、ありがとうございました。 | ||||||||||||
|
投稿日時: 2006-04-19 16:44
はい。 方法というより、先に書いたように依存しているオブジェクトが変動することがよくありません。 #してはいけないと言ったほうがよいかもしれません。 For Each hControl As Control In GroupBoxA.Controls この場合、毎回GroupBoxA.Controls.GetEnumeratorが呼び出されます。 つまり毎回GroupBoxA.Controlsの状態を参照してそれに依存しているわけです。 #実際の挙動ではありません たとえば、GetEnumeratorが呼び出し側に返した数を管理しているとします。 すると返す際に現在の総数-返した数が残りとなります。 返した数は+1、残りは−1かつ呼び出し側で削除した分−1となり 囚人さんがおっしゃるように元の総数の半分で終了することになります。 対して For i As Integer = 0 to GroupBoxA.Controls.Count - 1 この場合、For文でGroupBoxA.Controls.Countが評価されて値に置き換わります。 したがって構文上ループ回数が変動することはありません。 | ||||||||||||
|
投稿日時: 2006-04-19 16:52
ちなみに、スレッド処理では考慮していないと
今回のように変動するような実装が無くても似たようなことが起こります。 #ヘルプ「マネージスレッド処理の実施」内の「競合状態」を参照 ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.VisualStudio.v80.ja/dv_fxadvance/html/e51988e7-7f4b-4646-a06d-1416cee8d557.htm 同一オブジェクトをいろんなところから同時に操作するという場合です。 [ メッセージ編集済み 編集者: まどか 編集日時 2006-04-19 16:53 ] | ||||||||||||
|
投稿日時: 2006-04-19 16:54
さかもとです。
まどか様、ご丁寧にありがとうございます。 >この場合、毎回GroupBoxA.Controls.GetEnumeratorが呼び出されます。 >つまり毎回GroupBoxA.Controlsの状態を参照してそれに依存しているわけです。 なるほど、内部ではこのようになっているわけですね。 「毎回」という部分に関して勘違いしていました。 「ある時点での状態」を保持してそれを都度見に行っているわけでは ないと・・・。 頭のモヤモヤがすっきりしました(笑) お時間頂戴しまして、申し訳ありませんでした。 ありがとうございました。 |