WinFormsでMenuStripとDockStyleをFillにしたPanelの表示順番

C# コンピュータ
C#

フォームのメニューバーを構成するMenuStripとDockSytleをFillにしたPanelを同じフォームのクライアント領域に配置した場合どの様に表示されるでしょうか?筆者的自然な形はメニューバーが表示され残された領域一杯にPanelが表示されることを期待します。

1.メニューバーのみ作成します。

namespace MenuORDock01;

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        // メニューバーの作成
        MenuStrip menuBar = new();

        // メニュー「ファイル」項目作成
        ToolStripMenuItem menuItemFile = new()
        {
            Text = "ファイル",
        };
        // メニューバーへ追加
        menuBar.Items.Add(menuItemFile);

        // メニューバーをフォームに登録
        this.Controls.Add(menuBar);
    }
}

実行するとメニューが表示されます。

MenuStripの場合、LocationやSizeなどで配置する位置やサイズを指定しなくとも、フォームに登録するだけでフォームの上部に張り付きます。

2.メニューバーとパネルを作成してみます。

namespace MenuORDock01;

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        // メニューバーの作成
        MenuStrip menuBar = new();

        // メニュー「ファイル」項目作成
        ToolStripMenuItem menuItemFile = new()
        {
            Text = "ファイル",
        };
        // メニューバーへ追加
        menuBar.Items.Add(menuItemFile);

        // メニューバーをフォームに登録
        this.Controls.Add(menuBar);

        // パネルを作成
        Panel panel = new ()
        {
            BackColor = Color.Yellow,  // 黄色
            Dock = DockStyle.Fill   // 領域一杯に広げる
        };
        // パネルをフォームに登録
        this.Controls.Add(panel);

    }
}

実行するとメニュー以外が黄色く塗りつぶされ目が痛いです。

MenuStripの領域以外がPanelで埋め尽くされた状態になりました。

3.パネル⇒メニューの順番で登録

namespace MenuORDock01;

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        // メニューバーの作成
        MenuStrip menuBar = new();

        // メニュー「ファイル」項目作成
        ToolStripMenuItem menuItemFile = new()
        {
            Text = "ファイル",
        };
        // メニューバーへ追加
        menuBar.Items.Add(menuItemFile);

/*
        // メニューバーをフォームに登録 ↓へ移動
        this.Controls.Add(menuBar);
*/
        // パネルを作成
        Panel panel = new ()
        {
            BackColor = Color.Yellow,  // 黄色
            Dock = DockStyle.Fill   // 領域一杯に広げる
        };
        // パネルをフォームに登録
        this.Controls.Add(panel);

        // メニューバーをフォームに登録
        this.Controls.Add(menuBar);
    }
}


順番を変えても結果は一緒になりました。

4.ステータスバーを追加してみる。

namespace MenuORDock01;

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        // メニューバーの作成
        MenuStrip menuBar = new();

        // メニュー「ファイル」項目作成
        ToolStripMenuItem menuItemFile = new()
        {
            Text = "ファイル",
        };
        // メニューバーへ追加
        menuBar.Items.Add(menuItemFile);

/*
        // メニューバーをフォームに登録 ↓へ移動
        this.Controls.Add(menuBar);
*/
        // パネルを作成
        Panel panel = new ()
        {
            BackColor = Color.Yellow,  // 黄色
            Dock = DockStyle.Fill   // 領域一杯に広げる
        };
        // パネルをフォームに登録
        this.Controls.Add(panel);

        // メニューバーをフォームに登録
        this.Controls.Add(menuBar);

        // ステータスバー
        StatusStrip statusBar1 = new();
        ToolStripStatusLabel statusLabel1 = new()
        {
            Text = "ステータスバー",
        };
        
        statusBar1.Items.Add(statusLabel1);
        //ステータスバーをフォームに登録
        this.Controls.Add(statusBar1);
    }

}

実行するとステータスバーがフォーム下部に張り付く

5.ツールバーを追加

namespace MenuORDock01;


public class ToolStripSpringTextBox : ToolStripTextBox
{
    public override Size GetPreferredSize(Size constrainingSize)
    {
        if (Owner is null) return DefaultSize;
        // Use the default size if the text box is on the overflow menu
        // or is on a vertical ToolStrip.
        if (IsOnOverflow || Owner.Orientation == Orientation.Vertical)
        {
            return DefaultSize;
        }

        // Declare a variable to store the total available width as
        // it is calculated, starting with the display width of the
        // owning ToolStrip.
        Int32 width = Owner.DisplayRectangle.Width;

        // Subtract the width of the overflow button if it is displayed.
        if (Owner.OverflowButton.Visible)
        {
            width = width - Owner.OverflowButton.Width -
                Owner.OverflowButton.Margin.Horizontal;
        }

        // Declare a variable to maintain a count of ToolStripSpringTextBox
        // items currently displayed in the owning ToolStrip.
        Int32 springBoxCount = 0;

        foreach (ToolStripItem item in Owner.Items)
        {
            // Ignore items on the overflow menu.
            if (item.IsOnOverflow) continue;

            if (item is ToolStripSpringTextBox)
            {
                // For ToolStripSpringTextBox items, increment the count and
                // subtract the margin width from the total available width.
                springBoxCount++;
                width -= item.Margin.Horizontal;
            }
            else
            {
                // For all other items, subtract the full width from the total
                // available width.
                width = width - item.Width - item.Margin.Horizontal;
            }
        }

        // If there are multiple ToolStripSpringTextBox items in the owning
        // ToolStrip, divide the total available width between them.
        if (springBoxCount > 1) width /= springBoxCount;

        // If the available width is less than the default width, use the
        // default width, forcing one or more items onto the overflow menu.
        if (width < DefaultSize.Width) width = DefaultSize.Width;

        // Retrieve the preferred size from the base class, but change the
        // width to the calculated width.
        Size size = base.GetPreferredSize(constrainingSize);
        size.Width = width;
        return size;
    }
}

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        // メニューバーの作成
        MenuStrip menuBar = new();

        // メニュー「ファイル」項目作成
        ToolStripMenuItem menuItemFile = new()
        {
            Text = "ファイル",
        };
        // メニューバーへ追加
        menuBar.Items.Add(menuItemFile);

/*
        // メニューバーをフォームに登録 ↓へ移動
        this.Controls.Add(menuBar);
*/
        // パネルを作成
        Panel panel = new ()
        {
            BackColor = Color.Yellow,  // 黄色
            Dock = DockStyle.Fill,   // 領域一杯に広げる

        };
        // パネルをフォームに登録
        this.Controls.Add(panel);

        // メニューバーをフォームに登録
        this.Controls.Add(menuBar);

        // ステータスバー
        StatusStrip statusBar1 = new();
        ToolStripStatusLabel statusLabel1 = new()
        {
            Text = "ステータスバー",
        };
        
        statusBar1.Items.Add(statusLabel1);
        //ステータスバーをフォームに登録
        this.Controls.Add(statusBar1);

        // ツールバー
        ToolStrip toolBar = new ();

        ToolStripSpringTextBox addressBar = new()
        {
            Text = "アドレスバー",
        };
        ToolStripButton execBtn = new()
        {
            Text = "実行",
        };
        toolBar.Items.Add(addressBar);
        toolBar.Items.Add(execBtn);
        //ツールバーをフォームに登録
        this.Controls.Add(toolBar);
    }

}

ToolStripSpringTextBoxという謎のクラスが増えていますが、こちらはマイクロソフトのサイトから拝借してきました。
方法: ToolStripTextBox をストレッチして ToolStrip の残りの幅を埋める - Windows Forms .NET Framework
Windows フォームで ToolStripTextBox を ToolStrip の残りの幅まで拡張する方法を学びます。

ToolStripTextBoxの機能を拡張し、ウェブブラウザのアドレスバーの様に領域一杯にテキストボックスの幅を広げます。
ウィンドウサイズの変更にも追従します。

ツールバーを追加しましたが、メニューバーの上に配置されました。

6。ツールバーとメニューバーの登録順の入れ替え

namespace MenuORDock01;


public class ToolStripSpringTextBox : ToolStripTextBox
{
    public override Size GetPreferredSize(Size constrainingSize)
    {
        if (Owner is null) return DefaultSize;
        // Use the default size if the text box is on the overflow menu
        // or is on a vertical ToolStrip.
        if (IsOnOverflow || Owner.Orientation == Orientation.Vertical)
        {
            return DefaultSize;
        }

        // Declare a variable to store the total available width as
        // it is calculated, starting with the display width of the
        // owning ToolStrip.
        Int32 width = Owner.DisplayRectangle.Width;

        // Subtract the width of the overflow button if it is displayed.
        if (Owner.OverflowButton.Visible)
        {
            width = width - Owner.OverflowButton.Width -
                Owner.OverflowButton.Margin.Horizontal;
        }

        // Declare a variable to maintain a count of ToolStripSpringTextBox
        // items currently displayed in the owning ToolStrip.
        Int32 springBoxCount = 0;

        foreach (ToolStripItem item in Owner.Items)
        {
            // Ignore items on the overflow menu.
            if (item.IsOnOverflow) continue;

            if (item is ToolStripSpringTextBox)
            {
                // For ToolStripSpringTextBox items, increment the count and
                // subtract the margin width from the total available width.
                springBoxCount++;
                width -= item.Margin.Horizontal;
            }
            else
            {
                // For all other items, subtract the full width from the total
                // available width.
                width = width - item.Width - item.Margin.Horizontal;
            }
        }

        // If there are multiple ToolStripSpringTextBox items in the owning
        // ToolStrip, divide the total available width between them.
        if (springBoxCount > 1) width /= springBoxCount;

        // If the available width is less than the default width, use the
        // default width, forcing one or more items onto the overflow menu.
        if (width < DefaultSize.Width) width = DefaultSize.Width;

        // Retrieve the preferred size from the base class, but change the
        // width to the calculated width.
        Size size = base.GetPreferredSize(constrainingSize);
        size.Width = width;
        return size;
    }
}

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        // メニューバーの作成
        MenuStrip menuBar = new();

        // メニュー「ファイル」項目作成
        ToolStripMenuItem menuItemFile = new()
        {
            Text = "ファイル",
        };
        // メニューバーへ追加
        menuBar.Items.Add(menuItemFile);

/*
        // メニューバーをフォームに登録 ↓へ移動
        this.Controls.Add(menuBar);
*/
        // パネルを作成
        Panel panel = new ()
        {
            BackColor = Color.Yellow,  // 黄色
            Dock = DockStyle.Fill,   // 領域一杯に広げる

        };
        // パネルをフォームに登録
        this.Controls.Add(panel);

/*
        // メニューバーをフォームに登録 ↓へ移動
        this.Controls.Add(menuBar);
*/
        // ステータスバー
        StatusStrip statusBar1 = new();
        ToolStripStatusLabel statusLabel1 = new()
        {
            Text = "ステータスバー",
        };
        
        statusBar1.Items.Add(statusLabel1);
        //ステータスバーをフォームに登録
        this.Controls.Add(statusBar1);

        // ツールバー
        ToolStrip toolBar = new ();

        ToolStripSpringTextBox addressBar = new()
        {
            Text = "アドレスバー",
        };
        ToolStripButton execBtn = new()
        {
            Text = "実行",
        };
        toolBar.Items.Add(addressBar);
        toolBar.Items.Add(execBtn);
        //ツールバーをフォームに登録
        this.Controls.Add(toolBar);
        
        // メニューバーをフォームに登録
        this.Controls.Add(menuBar);

    }

}

登録順をツールバーの後にメニューバーにしたところメニューバーが上に表示されました。

今回わかったこと

・ToolStrip系のコントロールと通常のコントロールのDockStyleは、ToolStripの領域を確保したあと、DockStyleが適用されている模様
・ToolStrip系のコントロールは自動で配置されるが、後から登録したコントロールが優先?される模様

コメント