.NET の Form.MdiChildren Property 更新ポイント|MDI 子フォーム管理で確認すべき実務ポイント

.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 アプリでも安全に保守しやすくなります。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次