【C#】Formの中にFormを表示して良い感じに切り替える

この記事は約 8 分で読めます。

今回めちゃくちゃニッチな技術の紹介をしたいと思います。

その名は!

Formの中にFormを表示する!という技術!

これ使いどころどこなんや??ってレベルで、ニッチなのですが、この技術が平気で使えると1画面の中でいろいろな画面を表示できるので結構おすすめです!

それでは早速!

Formを4つ作成

MainFormはForm切り替え用のButtonを配置

まずはこんな感じでPanelを適当に二つ配置

Dockを良い感じにいじったら上記のように整った形になる

Dockはプロパティにある。

でForm切り替え用のボタンを配置していく

これもまずは適当に配置して

今回はDockを全てTopにすると上記のように整った

高さを良い感じに合わせて

スタイルを良い感じに整えたらとりあえずMainFormは終わり

MainFormに入れるFormは設定を気を付けて!

ここからはMainFormの中に入れるFormを追加していくが、注意が必要。

とりあえずFormを追加すると下記のような感じになる。

でもこのままだとFormの中に✖ボタンを持ったFormが表示され不格好になるので、プロパティを一つ変える

SubFormはヘッダーと✖ボタンを消す!

FormBorderStyleをNoneにしただけで下記のようになる。

これならいい感じに表示できそう!

こんな感じでサイズが変わってもど真ん中に配置される世にしておく

サイズが変わった時でも配置を良い感じにしたいときはAnchorプロパティを触っておく

これはTopとすると上からの配置は固定、Bottomとすると下からの配置は固定といった感じになる。

その際に注意が必要なのが、下記のようにガイドに沿ってちゃんとコントロールを置いておくこと!

ちゃんと上みたいな感じでガイドが出るのでそれに合わせること!

こんな感じでほかのフォームも作る。

ここまでくれば下準備は完了!

MainFormロード時に下記コードを実行するようにする。

でMainFormのロード時に下記のようなメソッドを実行するようにしておく

namespace FormInForm
{
    public partial class MainForm : Form
    {
        private Form form1;
        private Form form2;
        private Form form3;

        public MainForm()
        {
            InitializeComponent();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            form1 = new Form1();
            form1.TopLevel = false;
            form1.Dock = DockStyle.Fill;
            panel2.Controls.Add(form1);

            form2 = new Form2();
            form2.TopLevel = false;
            form2.Dock = DockStyle.Fill;
            panel2.Controls.Add(form2);

            form3 = new Form3();
            form3.TopLevel = false;
            form3.Dock = DockStyle.Fill;
            panel2.Controls.Add(form3);

            form1.Show();
        }
    }
}

するとこんな感じでMainFormの中にForm1が表示された状態で立ち上がった

サイズが変わってもこの通り!

ちゃんと真ん中にLabelがよって良い感じ!

ボタンにメソッドを追加していく

        private void button1_Click(object sender, EventArgs e)
        {
            HideAllForm();
            form1.Show();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            HideAllForm();
            form2.Show();
        }

        private void button3_Click(object sender, EventArgs e)
        {
            HideAllForm();
            form3.Show();
        }

        private void HideAllForm()
        {
            form1.Hide();
            form2.Hide();
            form3.Hide();
        }

ボタンを押すとこんな感じ!

Form1ボタンを押した

Form2ボタンを押した

Form3ボタンを押した

アクティブなFormのButtonの色を変える

このままだとどのFormがアクティブなのかいまいちわかりずらい。

っていうのも今回はForm1とかForm2といったLabelを貼っているが、実際はただコントロールが配置されているだけだからである。

なので、今アクティブになっているFormのButtonの色を変えることで、わかりやすくしたいと思う。

    public partial class MainForm : Form
    {
        private Form form1;
        private Form form2;
        private Form form3;

        private Color _activeColor = Color.Aquamarine;
        private Color _defaultColor = Color.CadetBlue;

こんな感じでアクティブなボタンの色を設定して

ロード時に表示しているFormのボタンの色が変わるようにしておく

        private void MainForm_Load(object sender, EventArgs e)
        {
            form1 = new Form1();
            form1.TopLevel = false;
            form1.Dock = DockStyle.Fill;
            panel2.Controls.Add(form1);

            form2 = new Form2();
            form2.TopLevel = false;
            form2.Dock = DockStyle.Fill;
            panel2.Controls.Add(form2);

            form3 = new Form3();
            form3.TopLevel = false;
            form3.Dock = DockStyle.Fill;
            panel2.Controls.Add(form3);

            button1.BackColor = _activeColor;
            form1.Show();
        }

で、各ボタンを押したときに下記のメソッドを追加

        private void button1_Click(object sender, EventArgs e)
        {
            form2.Hide();
            form3.Hide();

            form1.Show();

            button2.BackColor = _defaultColor;
            button3.BackColor = _defaultColor;

            button1.BackColor = _activeColor;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            form1.Hide();
            form3.Hide();

            form2.Show();

            button1.BackColor = _defaultColor;
            button3.BackColor = _defaultColor;

            button2.BackColor = _activeColor;
        }

        private void button3_Click(object sender, EventArgs e)
        {
            form1.Hide();
            form2.Hide();

            form3.Show();

            button1.BackColor = _defaultColor;
            button2.BackColor = _defaultColor;

            button3.BackColor = _activeColor;
        }

こうするといい感じに色が変わった!

リアファクタリング

ただこれだと、SubFormが増えた時にめっちゃ面倒なコード。

というのも

        private void button2_Click(object sender, EventArgs e)
        {
            form1.Hide();
            form3.Hide();

            form2.Show();

            button1.BackColor = _defaultColor;
            button3.BackColor = _defaultColor;

            button2.BackColor = _activeColor;
        }

各ボタンで上記の実装をしているので、Formが増えるたびに追加したりして対応しないといけない。

これだと面倒すぎるので、リファクタリングしていく。

まずはこんな感じでFormとボタンのリストを作っていく

    public partial class MainForm : Form
    {
        private Form form1;
        private Form form2;
        private Form form3;

        private IEnumerable<Form> _subForms;
        private IEnumerable<Button> _formButtons;

ロードイベントでnewする

        private void MainForm_Load(object sender, EventArgs e)
        {
            form1 = new Form1();
            form1.TopLevel = false;
            form1.Dock = DockStyle.Fill;
            panel2.Controls.Add(form1);

            form2 = new Form2();
            form2.TopLevel = false;
            form2.Dock = DockStyle.Fill;
            panel2.Controls.Add(form2);

            form3 = new Form3();
            form3.TopLevel = false;
            form3.Dock = DockStyle.Fill;
            panel2.Controls.Add(form3);

            // ここでフィールドのリストを作る
            _subForms = new List<Form>()
            {
                form1,form2,form3
            };

            // ここでフィールドのリストを作る
            _formButtons = new List<Button>()
            {
                button1,button2,button3
            };

            button1.BackColor = _activeColor;
            form1.Show();
        }

で下記のメソッドを作る

        private void ShowForm(Form form)
        {
            // subFormの配列をぶん回して引数のFormと一致してたら表示して、
            // 一致してなかったら隠す
            foreach (var f in _subForms)
            {
                if (f == form)
                {
                    f.Show();
                }
                else
                {
                    f.Hide();
                }
            }
        }

        private void ActivateBtn(Button btn)
        {
            // form表示するボタンのリストをぶん回して、
            // 引数のボタンを一致してたらactiveColorにして、
            // 一致してなかったらdefaultColorにする
            foreach (var b in _formButtons)
            {
                b.BackColor = b == btn ? _activeColor : _defaultColor;
            }
        }

このコードがあればボタンを押したときのメソッドがめちゃくちゃ短くなる。

        private void button1_Click(object sender, EventArgs e)
        {
            ShowForm(form1);
            ActivateBtn((Button)sender);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            ShowForm(form2);
            ActivateBtn((Button)sender);
        }

        private void button3_Click(object sender, EventArgs e)
        {
            ShowForm(form3);
            ActivateBtn((Button)sender);
        }

これで動きは一緒だったらいい感じ!

良い感じ!!

今回のコードはGithubに上げています!

今回のサンプルコード「FormInForm」というタイトルで下記Githubに上げています!

https://github.com/adaman3568/blog-source-demo

是非ローカルで触ってみてください!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA