C# - モーダルなサブウィンドウを開くサンプルコードべた書き（Visual Studio不使用）

`Form`の画面レイアウトが一杯になってきて設定画面を切り離したいときとかに、子ウィンドウを出したくなると思います。
今回はモーダルウィンドウ（閉じるまで親の`Form`を操作できない）を表示させます。

[モーダルウィンドウ　モードレスウィンドウ - Google検索](https://www.google.co.jp/search?q=%E3%83%A2%E3%83%BC%E3%83%80%E3%83%AB%E3%82%A6%E3%82%A3%E3%83%B3%E3%83%89%E3%82%A6+%E3%83%A2%E3%83%BC%E3%83%89%E3%83%AC%E3%82%B9%E3%82%A6%E3%82%A3%E3%83%B3%E3%83%89%E3%82%A6)

# 画面キャプチャ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438183/dcaadd59-7540-b2e6-6040-44e235385f43.png)


# サンプルソースコード

```csharp

using System;
using System.Drawing;
using System.Windows.Forms;

class MainForm : Form
{
    MainForm()
    {
        Text = "Main window";
        ClientSize = new Size(400,300);
        
        var btn = new Button(){
            Size = new Size(200,50),
            Text = "Show sub window.",
        };
        Controls.Add(btn);
        btn.Click += (s,e)=>{ ShowSubFormWithText("this is a sample."); };
    }

    static void ShowSubFormWithText(string text)
    {
        SubForm f = new SubForm(text);
        f.ShowDialog();
    }

    [STAThread]
    static void Main(string[] args)
    {
        Application.Run(new MainForm());
    }
}


class SubForm : Form
{
    public SubForm(string text)
    {
        Text = "Sub window";
        ClientSize = new Size(300,150);
        StartPosition = FormStartPosition.CenterParent;
        // StartPosition = FormStartPosition.CenterScreen;
        
        var txt = new TextBox(){
            Text = text,
            Multiline = true,
            ScrollBars = ScrollBars.Both,
            Dock = DockStyle.Fill
        };
        
        txt.KeyDown += (sender,e)=>{
            if (e.Control && e.KeyCode == Keys.A) { txt.SelectAll(); }
        };
        
        Controls.Add(txt);
    }
}
```

# サブウィンドウから結果データを受け取りたい場合

参考サイト2を参考に作成しました。

```csharp

using System;
using System.Drawing;
using System.Windows.Forms;

class MainForm : Form
{
    MainForm()
    {
        Text = "Main window";
        ClientSize = new Size(400,300);
        
        var btn = new Button(){
            Size = new Size(200,50),
            Text = "Show sub window.",
        };
        Controls.Add(btn);
        btn.Click += (s,e)=>{ ShowSubFormWithText("this is a sample."); };
    }

    static void ShowSubFormWithText(string text)
    {
        SubForm f = new SubForm(text);
        DialogResult res = f.ShowDialog();
        Console.WriteLine(res); // DialogResultの確認用
        Console.WriteLine(f.Value); // 結果データの確認用

        if ( res == DialogResult.OK ) {
            // ... OKが押されたときの処理
        }
    }

    [STAThread]
    static void Main(string[] args)
    {
        Application.Run(new MainForm());
    }
}


class SubForm : Form
{
    public string Value;
    TextBox txt;

    public SubForm(string text)
    {
        Value = "";

        Text = "Sub window";
        ClientSize = new Size(300,200);
        StartPosition = FormStartPosition.CenterParent;
        // FormBorderStyle = FormBorderStyle.FixedSingle; // サイズ変更不可にする場合

        txt = new TextBox(){
            Location =new Point(0, 0),
            Size = new Size(300, 160),
            Text = text,
            Multiline = true,
            ScrollBars = ScrollBars.Both,
        };
        txt.KeyDown += (s,e)=>{
            if (e.Control && e.KeyCode == Keys.A) { txt.SelectAll(); }
        };

        Controls.Add(txt);


        var btn1 = new Button(){
            Location =new Point(0, 160),
            Size = new Size(150, 40),
            Text = "OK",
        };
        var btn2 = new Button(){
            Location =new Point(150, 160),
            Size = new Size(150, 40),
            Text = "Cancel",
        };
        btn1.Click += (s,e)=>{
            DialogResult = DialogResult.OK;
            Close();
        };
        btn2.Click += (s,e)=>{
            DialogResult = DialogResult.Cancel;
            Close();
        };
        Controls.Add(btn1);
        Controls.Add(btn2);


        FormClosed += (s,e)=>{Value = txt.Text;}; // SubFormが閉じられたときにデータをセットしておく
    }
}
```

サブウィンドウ`f`が閉じて(`FormClosed`)からも、`f`を参照している限りはガベージコレクションの対象にはならないので、`f`のフィールド`Value`を取得することができる[^1]。
という理屈のはず。

[^1]: 直接フィールドを参照するのはキモチワルイ気がするが、できるだけシンプルなサンプルになるようにフィールドを使用した。

# 参考サイト

 1. [フォームを画面の真ん中（あるいは、任意の位置）に表示する - .NET Tips (VB.NET,C#...)](https://dobon.net/vb/dotnet/form/startposition.html)
 2. [モーダルフォームとの間でデータや値の受け渡しをする - C#プログラミング](https://www.ipentec.com/document/csharp-modal-form-data-transfer)