.NET の Form.MdiChildren は、Windows Forms の MDI 親フォームにぶら下がっている子フォームを Form[] として取得する読み取り専用プロパティです。2026年7月1日に公開または更新された Microsoft Learn の内容を見る限り、MdiChildren に新しい設定項目や移行期限が追加されたというより、既存の MDI アプリで「開いている子画面をどう安全に列挙するか」を確認するための API と捉えるのが実務的です。対象になるのは、業務アプリや管理ツールなどで Windows Forms の MDI 構成を使っている .NET アプリです。公式ドキュメントでも、MdiChildren は MDI 親フォームに属する MDI 子フォームを表す配列を取得するプロパティとして説明されています。(Microsoft Learn)
.NET の Form.MdiChildren Property とは
Form.MdiChildren は、System.Windows.Forms.Form クラスに用意されているプロパティです。MDI は Multiple Document Interface の略で、1つの親ウィンドウの中に複数の子ウィンドウを表示する古典的なデスクトップ UI パターンです。
たとえば、次のようなアプリで使われます。
| 利用シーン | MDI の使われ方 | MdiChildren の役割 |
|---|---|---|
| 販売管理システム | 顧客画面、受注画面、在庫画面を親フォーム内で開く | 開いている子画面をまとめて取得する |
| 社内向け管理ツール | 複数の設定画面やログ画面を同時に表示する | 一括保存、一括更新、終了前チェックに使う |
| レガシー WinForms アプリ | .NET Framework 時代からの MDI UI を継続利用する | 既存コードの保守で子フォーム一覧を確認する |
公式情報では、MdiChildren の型は System.Windows.Forms.Form[] で、get のみを持つ読み取り専用プロパティです。プロパティ値は、このフォームの MDI 子フォームを識別する Form オブジェクトの配列です。(Microsoft Learn)
public System.Windows.Forms.Form[] MdiChildren { get; }
つまり、MdiChildren は「子フォームを登録するためのプロパティ」ではありません。子フォームを作成するには、子フォーム側の MdiParent に親フォームを設定します。公式ドキュメントでも、MDI 子フォームを作成するには、子フォームの MdiParent プロパティに MDI 親フォームを割り当てると説明されています。(Microsoft Learn)
2026年7月1日更新情報で確認すべきポイント
今回の Form.MdiChildren Property の確認で重要なのは、「新機能として何かを有効化する」というより、既存の Windows Forms アプリにおける MDI 子フォーム管理を正しく理解することです。
| 確認項目 | 実務上の判断 |
|---|---|
| API の役割 | MDI 親フォームに現在関連付けられている子フォームの配列を取得する |
| 変更の性質 | 設定変更や管理画面の追加ではなく、API リファレンスとしての確認が中心 |
| 対象アプリ | Windows Forms で MDI を使っている .NET デスクトップアプリ |
| 影響を受けにくいアプリ | WPF、ASP.NET、Blazor、MAUI、コンソールアプリなど、WinForms MDI を使わないアプリ |
| 管理者の確認点 | 配布対象アプリに MDI 画面があるか、終了処理・保存処理で子フォームを列挙しているか |
| 移行期限 | MdiChildren 自体に固有の移行期限は示されていない |
特に注意したいのは、Microsoft Learn の該当ページが windowsdesktop-10.0 ビューで表示される場合、プレリリース製品に関する情報が含まれる可能性があるという注意書きがある点です。API の基本的な使い方は従来の Windows Forms と整合しますが、対象フレームワークやビルド環境を確認する場合は、利用中の .NET バージョンに合わせてドキュメントの表示バージョンを切り替えるのが安全です。(Microsoft Learn)
MdiChildren の基本的な使い方
MdiChildren は、親フォーム側から開いている MDI 子フォームをまとめて処理したいときに使います。代表的なのは、親フォームを閉じる前に子フォームの未保存データを確認する処理です。
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
foreach (Form child in this.MdiChildren)
{
if (child is IConfirmClose confirmClose)
{
if (!confirmClose.CanClose())
{
e.Cancel = true;
child.Activate();
return;
}
}
}
}
この例では、MDI 子フォームが IConfirmClose という独自インターフェイスを実装している場合だけ、終了可能かどうかを確認しています。すべての子フォームに同じ処理を無理に適用するのではなく、対象フォームを型で判定しているのがポイントです。
MDI 子フォームを作成する基本形は次のとおりです。
private void OpenCustomerForm()
{
var child = new CustomerForm();
child.MdiParent = this;
child.Text = "顧客管理";
child.Show();
}
MdiChildren にフォームを直接追加するのではなく、子フォームの MdiParent に親フォームを設定します。MdiParent に指定できるのは MDI コンテナーとして設定されたフォームであり、公式情報でも、割り当て先フォームが MDI コンテナーでない場合や、別スレッド上にある場合などは例外の対象になると説明されています。(Microsoft Learn)
IsMdiContainer、MdiParent、MdiChildren の関係
MdiChildren を理解するには、関連する3つのプロパティをセットで押さえると迷いにくくなります。
| プロパティ | 設定・取得 | 主な用途 |
|---|---|---|
IsMdiContainer | 取得・設定 | そのフォームを MDI 親フォームとして使うかを指定する |
MdiParent | 取得・設定 | 子フォーム側で、どのフォームを親にするかを指定する |
MdiChildren | 取得のみ | 親フォーム側で、現在の MDI 子フォーム一覧を取得する |
IsMdiChild | 取得のみ | そのフォームが MDI 子フォームかどうかを判定する |
IsMdiContainer を true にすると、そのフォームは MDI 子フォームのコンテナーとして動作します。公式ドキュメントでは、IsMdiContainer が MDI 子フォームのコンテナーかどうかを示すプロパティであり、既定値は false とされています。(Microsoft Learn)
典型的な流れは次のようになります。
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
// 親フォームを MDI コンテナーにする
this.IsMdiContainer = true;
}
private void menuOpen_Click(object sender, EventArgs e)
{
var child = new OrderForm();
// 子フォームをこの親フォームに所属させる
child.MdiParent = this;
child.Show();
}
private void menuCloseAll_Click(object sender, EventArgs e)
{
foreach (Form child in this.MdiChildren)
{
child.Close();
}
}
}
このコードのように、MdiChildren は「親フォームに所属している子フォームを後からまとめて扱う」場面で使います。子フォームを開く処理、閉じる処理、一括保存、一括更新を整理すると、MDI アプリの保守性が大きく上がります。
影響範囲:どのアプリが確認対象になるか
Form.MdiChildren の影響範囲は広く見えて、実際にはかなり限定的です。確認すべきなのは、Windows Forms で MDI を使っているアプリです。
| 対象 | 確認の必要性 | 理由 |
|---|---|---|
| WinForms の MDI 業務アプリ | 高い | MdiChildren を終了処理や保存処理で使っている可能性がある |
| .NET Framework から .NET へ移行中の WinForms アプリ | 高い | 移行時に MDI 周辺の挙動確認が必要になりやすい |
| WinForms だが MDI を使っていないアプリ | 低い | MdiChildren の利用箇所がなければ直接影響は小さい |
| WPF アプリ | 原則対象外 | System.Windows.Forms.Form の MDI 機能ではない |
| ASP.NET、Blazor、Web API | 対象外 | サーバーサイドまたは Web UI の仕組みであり、WinForms MDI とは別物 |
| Microsoft 365 管理者設定 | 対象外 | テナント設定やクラウド管理機能ではない |
管理者や運用担当者が見るべきなのは、サーバー設定やクラウドポリシーではなく、配布しているクライアントアプリの種類です。たとえば、社内に ClickOnce、MSI、Intune、ConfigMgr などで配布している WinForms アプリがあり、そのアプリが MDI 形式の画面を持っている場合は確認対象になります。
設定変更は必要か
Form.MdiChildren 自体には、管理センターで有効化するような設定変更はありません。コード上で参照するプロパティであり、設定値を変更して動作を切り替えるタイプの機能ではないためです。
ただし、アプリ側では次の設定・実装を確認する必要があります。
| 確認箇所 | 確認する内容 | 問題がある場合の例 |
|---|---|---|
| 親フォーム | IsMdiContainer = true が設定されているか | MdiParent 設定時に例外が発生する |
| 子フォーム作成処理 | child.MdiParent = this の後に Show() しているか | 子フォームが親フォーム内に表示されない |
| 終了処理 | MdiChildren を列挙して未保存データを確認しているか | 親フォーム終了時に子フォームの変更が失われる |
| 一括更新処理 | 対象フォームだけを型判定して処理しているか | 関係ない子フォームまで更新される |
| スレッド | UI スレッド上でフォームを操作しているか | 別スレッドからの UI 操作で例外や不安定動作につながる |
特に MdiParent は、割り当て先が MDI コンテナーでない場合や別スレッド上にある場合に例外となる可能性があります。これは MdiChildren の問題というより、MDI フォーム構成そのものの前提条件です。(Microsoft Learn)
移行期限はあるか
2026年7月1日公開または更新の Form.MdiChildren Property 情報において、MdiChildren 自体の廃止や移行期限は示されていません。したがって、すぐにコードを書き換える必要がある種類の更新ではありません。
ただし、実務では次のようなタイミングで確認しておく価値があります。
| タイミング | 確認すべきこと |
|---|---|
| .NET Framework から新しい .NET へ移行する前 | MDI 子フォームの作成、列挙、終了処理が移行後も動くか |
| Windows Forms アプリを再ビルドする前 | 利用中のターゲットフレームワークと Windows Desktop SDK の組み合わせ |
| UI 改修で MDI を廃止・縮小する前 | MdiChildren に依存した一括保存や一括終了処理が残っていないか |
| 管理端末の OS 更新前 | 重要な WinForms 業務アプリが新環境で問題なく動くか |
| グローバル展開前 | ロケール、DPI、複数画面、入力言語の違いで MDI 画面が崩れないか |
MdiChildren の存在だけを見て移行判断をするのではなく、アプリ全体が MDI 前提で作られているかを確認することが重要です。MDI は古くからある UI パターンですが、社内向け業務アプリでは今も使われることがあります。無理に全面刷新するより、まずは列挙処理、保存処理、終了処理をテストで固める方が現実的です。
よくある実装ミスと対策
MdiChildren はシンプルなプロパティですが、実務では使い方を誤ると不具合につながります。
子フォームを閉じながら列挙して問題が起きる
MdiChildren を foreach で回しながら子フォームを閉じるコードはよくあります。
foreach (Form child in this.MdiChildren)
{
child.Close();
}
多くのケースではこの形で動きますが、子フォームの FormClosing イベント内で別の子フォームを開いたり閉じたりするような複雑な処理がある場合、列挙対象が途中で変わる可能性があります。安全側に倒すなら、配列を明示的にコピーしてから処理します。
Form[] children = this.MdiChildren.ToArray();
foreach (Form child in children)
{
child.Close();
}
MdiChildren は配列を返すため、通常のコレクション操作と同じ感覚で扱えます。ただし、フォームを閉じる処理はイベントを発生させるため、単純な一覧処理より副作用が大きい点に注意してください。
すべての子フォームを同じ型だと思い込む
MDI アプリでは、顧客画面、注文画面、ログ画面、検索画面など、複数種類のフォームが同時に開くことがあります。すべての子フォームを特定の型にキャストすると、想定外のフォームが開いていたときに失敗します。
避けたい例は次のようなコードです。
foreach (Form child in this.MdiChildren)
{
var orderForm = (OrderForm)child;
orderForm.Reload();
}
安全な書き方は、対象の型だけ処理する形です。
foreach (Form child in this.MdiChildren)
{
if (child is OrderForm orderForm)
{
orderForm.Reload();
}
}
業務アプリでは「受注明細だけ更新したい」「マスタ画面だけ再読み込みしたい」といったケースが多いため、型判定を入れるだけで保守性が上がります。
未保存データの確認を親フォームだけで済ませてしまう
MDI では、親フォームを閉じると子フォームにも閉じる処理が及びます。公式ドキュメントでは、MDI 親フォームが閉じられると、親フォームの Closing イベントより前に MDI 子フォームの Closing イベントが発生すると説明されています。(Microsoft Learn)
そのため、未保存データの確認を親フォームだけで行うと、個別の子フォームの状態を見落とすことがあります。実装方針としては、次のどちらかに整理すると安全です。
| 方針 | 向いているケース |
|---|---|
子フォームごとの FormClosing で確認する | 画面ごとに保存条件や確認メッセージが異なる |
親フォームで MdiChildren を列挙して確認する | 共通インターフェイスで未保存状態を管理している |
おすすめは、子フォームに共通インターフェイスを実装させ、親フォームでまとめて確認する方法です。
public interface IDirtyForm
{
bool HasChanges { get; }
bool ConfirmDiscardChanges();
}
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
foreach (Form child in this.MdiChildren)
{
if (child is IDirtyForm dirtyForm && dirtyForm.HasChanges)
{
child.Activate();
if (!dirtyForm.ConfirmDiscardChanges())
{
e.Cancel = true;
return;
}
}
}
}
この形にしておくと、画面ごとの実装差を吸収しながら、親フォーム側で一貫した終了制御ができます。
管理者・開発チームが確認すべきチェックリスト
Form.MdiChildren の更新ポイントを受けて、管理者や開発チームが確認すべき項目は次のとおりです。
| チェック項目 | 確認方法 | 優先度 |
|---|---|---|
| MDI を使っている WinForms アプリがあるか | ソースコードで IsMdiContainer、MdiParent、MdiChildren を検索する | 高 |
| 親フォーム終了時の処理があるか | FormClosing、FormClosed、メニューの終了処理を確認する | 高 |
| 未保存データの確認が子フォーム単位でできているか | 変更済みフラグ、保存確認ダイアログの実装を見る | 高 |
MdiChildren の列挙中にフォームを開閉していないか | foreach 内の Close()、Show()、Dispose() を確認する | 中 |
| 子フォームの型キャストが安全か | 直接キャストではなく is や共通インターフェイスを使っているか確認する | 中 |
| 移行対象の .NET バージョンで動作確認しているか | テスト環境で画面起動、切替、終了、保存を確認する | 中 |
| グローバル利用時の UI 差異を確認しているか | DPI、表示言語、日付形式、入力言語を変えてテストする | 中 |
コード検索では、まず次のキーワードを調べると効率的です。
MdiChildren
MdiParent
IsMdiContainer
IsMdiChild
ActiveMdiChild
MdiChildren だけでなく、MdiParent や IsMdiContainer も合わせて調べることで、MDI 構成の全体像を把握しやすくなります。
グローバル向け展開で注意したいポイント
要点に「グローバル向け」とある場合、単に英語 UI に対応するだけでは不十分です。MDI アプリはウィンドウ内に複数の子フォームを表示するため、表示倍率や画面サイズの違いが不具合として出やすい傾向があります。
確認したいのは次の点です。
| 観点 | 確認内容 |
|---|---|
| DPI スケーリング | 125%、150%、200% 表示で子フォームの位置やサイズが崩れないか |
| 多言語化 | ラベルの文字数増加でボタンや入力欄が隠れないか |
| 日付・数値形式 | ロケール変更で入力値の解析や表示が壊れないか |
| キーボード操作 | Alt キー、ショートカット、IME 利用時のフォーカス移動が自然か |
| 複数モニター | 親フォーム移動後も子フォーム操作に問題がないか |
| 終了処理 | 未保存の子フォームが複数ある場合に確認順序が分かりやすいか |
特に、複数の子フォームを一括保存する処理では、エラーが発生したフォームをユーザーに分かるように Activate() で前面に出すと運用しやすくなります。
foreach (Form child in this.MdiChildren)
{
if (child is ISaveTarget saveTarget)
{
try
{
saveTarget.Save();
}
catch (Exception ex)
{
child.Activate();
MessageBox.Show(
this,
$"保存に失敗しました: {child.Text}\n{ex.Message}",
"保存エラー",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
break;
}
}
}
グローバル展開では、例外メッセージをそのまま表示するのではなく、ユーザー向けメッセージとログ出力を分ける設計も重要です。MdiChildren は子フォームを見つける手段であり、エラー処理や監査ログの設計はアプリ側で補う必要があります。
Form.MdiChildren を使うべき場面・使わない場面
MdiChildren は便利ですが、すべての画面管理に使うべきではありません。目的に合う場面で使うのが大切です。
| 判断 | 具体例 |
|---|---|
| 使うべき場面 | 親フォーム終了時に、開いている子フォームを順番に確認する |
| 使うべき場面 | MDI 子フォーム全体にテーマ変更や再読み込みを反映する |
| 使うべき場面 | 特定種類の子フォームがすでに開いているか確認する |
| 使わない方がよい場面 | 通常のダイアログや非 MDI フォームを管理したい |
| 使わない方がよい場面 | アプリ全体の画面遷移を中央管理する目的で乱用する |
| 使わない方がよい場面 | MDI を使っていない新規アプリで、単に複数画面を扱いたいだけの場合 |
すでに開いている子フォームを再利用したい場合は、MdiChildren を検索して、存在しなければ新規作成する実装がよく使われます。
private void OpenOrActivateCustomerList()
{
foreach (Form child in this.MdiChildren)
{
if (child is CustomerListForm)
{
child.Activate();
return;
}
}
var form = new CustomerListForm
{
MdiParent = this
};
form.Show();
}
この実装により、同じ一覧画面が何枚も開いてしまう問題を防げます。業務アプリでは、同じマスタ画面や検索画面を重複して開かせないだけでも、問い合わせや入力ミスを減らせます。
まとめ:Form.MdiChildren は MDI 子フォーム管理の点検ポイント
.NET の Form.MdiChildren Property は、Windows Forms の MDI 親フォームに属する子フォームを Form[] として取得するためのプロパティです。2026年7月1日に公開または更新された公式情報を踏まえても、管理者がテナント設定を変更したり、特定日までに移行作業を完了したりするタイプの更新ではありません。確認すべき対象は、MDI を使っている WinForms アプリの実装です。
まずはソースコードで MdiChildren、MdiParent、IsMdiContainer を検索し、親フォーム終了時の保存確認、一括更新、子フォームの重複起動防止に使われている箇所を洗い出してください。そのうえで、利用中の .NET バージョン、配布環境、グローバル利用時の DPI やロケール差異を含めて動作確認すると、レガシーな MDI アプリでも安全に保守しやすくなります。

コメント