【学習】WinFormsの「ドラッグ&ドロップ」の正体を理解しよう(Controlsコレクション編)
シリーズ: WinFormsの「ドラッグ&ドロップ」の正体
Label編 では、Controls.Add によってコントロールが フォームに載る ところまで見ました。
ここから一歩進めて、
Controls は「子コントロールの一覧」であり、親子でつながっている
という仕組みを押さえます。Panel の中にボタンを置くような画面でも、同じ考え方がそのまま使えます。
今日学ぶこと
Controlsの意味 … そのコンテナ(フォームや Panel)の 子 を並べたコレクションであることAddと親子 …親.Controls.Add(子)と同時に子.Parentが親になること- 位置の基準 …
Locationは 親の左上 を原点にした座標であること - 列挙のイメージ …
foreachで回せるのは 直下の子だけ であり、孫は別のControlsにあること
Controls は「子のリスト」
Form も Panel も UserControl も、根っこは Control です。各 Control は、子を持つための Controls というプロパティを持っています。
イメージとしては次のような 入れ子のツリーです。
Form(this)
└─ Controls
├─ panel1
│ └─ Controls
│ └─ button1
└─ label1
デザイナで フォームに直接置いた コントロールは、this.Controls に並びます。Panel の上に置いた コントロールは、その Panel の panel1.Controls に並びます。
Controls.Add が決めること(親子の両面)
次の1行は、
this.Controls.Add(this.label1);
次の2つを 同時に 満たします。
| 側 | 意味 |
|---|---|
| 親(Form) | this.Controls に label1 が 登録される |
| 子(Label) | label1.Parent が この Form になる |
だから new しただけのコントロールは「宙に浮いたオブジェクト」で、Add されて初めて どのコンテナの子かが決まり、描画やマウス操作の対象として扱われます。
Remove や Clear をすると、登録が外れ、親子のつながりも変わります。
Location は「親から見た位置」
label1.Location = new Point(10, 20); の (10, 20) は、画面の絶対座標ではなく、親コントロールの左上からの距離です。
- フォーム直下なら フォームのクライアント領域の左上が原点
- Panel の子なら Panel の左上が原点
デザイナで Panel に入れたあと、同じ数値でも見え方が変わるのは、このためです。
列挙(foreach)で「全部」は取れない?
次のコードは、フォームの直下の子だけを列挙します。
foreach (Control c in this.Controls)
{
// c は「このフォームの子」1つずつ
}
Panel の中の Button は、this.Controls には 直接は出てきません。出てくるのは panel1 だけです。Button を見たければ、
foreach (Control c in this.panel1.Controls)
{
// panel1 の子
}
のように その親の Controls を見ます。
「画面にあるコントロール全部」を調べたい場合は、直下だけで終わらず 子の Controls に再帰的に入る必要があります(今回はイメージまで。必要になったらメソッド化して掘り下げます)。
デザイナのコードで確認する
Form1.Designer.cs の InitializeComponent では、だいたい次の順序が多いです。
- 子コントロールを
newしてプロパティを設定する - コンテナの
Controls.Addで子を載せる(入れ子なら内側から外側へ)
panel1.Controls.Add(this.button1); のあとに this.Controls.Add(this.panel1); のように、内側のコンテナから先に子を固めるイメージで読むと追いやすいです。
実験して理解する
ボタンの Click で、コードだけ Panel と Label を作って載せてみます。
private void button1_Click(object sender, EventArgs e)
{
var panel = new Panel();
panel.Location = new System.Drawing.Point(20, 20);
panel.Size = new System.Drawing.Size(200, 100);
panel.BorderStyle = BorderStyle.FixedSingle;
var lbl = new Label();
lbl.Text = "Panelの中";
lbl.Location = new System.Drawing.Point(10, 10);
panel.Controls.Add(lbl);
this.Controls.Add(panel);
}
lblはpanel.Controlsに入るので、見た目も座標も Panel 基準になるpanelはthis.Controlsに入るので、フォームの子になる
Label編の 「作る → 設定する → Add」 と同じ3拍子で、Add する親が違うと階層が変わることが手に取るように分かります。
まとめ
Controlsは、そのコントロールの 子一覧(コレクション)親.Controls.Add(子)で親子がつながり、子のLocationの原点も親になるforeach (Control c in this.Controls)は 直下だけ。孫は別のControlsを見る
次の記事
入門シリーズの Buttonのクリックイベント とあわせて読むと、次回の「+= の正体」がつながりやすいです。
目次は シリーズ固定ページ を参照してください。



ディスカッション
コメント一覧
まだ、コメントがありません