2017年3月29日水曜日

C# 複数のフォーム間でデータの受け渡しをする方法

複数のフォームでデータを行き来させたい場合、
どの様なやり方があるのか、調べてみた。

準備



新しいプロジェクトを作成



「Form1」へ
「ツールボックス」から
「Button」と「TextBox」を配置



「プロジェクト」->「新しい項目の追加」
で「Windowsフォーム」を追加する。



追加した「Form2」へ
「ツールボックス」から
「TextBox」を配置



「Form1」のボタンをダブルクリックして、
「クリック時イベント」のコードを表示させておきます。

1
2
3
4
private void button1_Click(object sender, EventArgs e)
{
 
}

「Form1」からモーダルで「Form2」を呼び出す



モーダルで「Form2」を呼び出すには2つの方法があります。
普段はリソースの解放が自動で行われる「using」の方を使います。
事情により使い分けます。

パターン1
1
2
3
4
5
6
private void button1_Click(object sender, EventArgs e)
{
    var subForm = new Form2();
    subForm.ShowDialog();
    subForm.Dispose();
}
パターン2(usingを使う)
1
2
3
4
5
6
7
private void button1_Click(object sender, EventArgs e)
{
    using (var subForm = new Form2())
    {
        subForm.ShowDialog();
    }
}
2つの方法のどちらかを記述して、
一度ここ迄で実行してみましょう。
ボタンを押すと「Form2」がモーダルで実行されるはずです。


Form間でデータの受け渡しを行う



「Form1」と「Form2」の間でデータの受け渡しを行います。

「Form2」へ
「ツールボックス」から
「Button」を配置して下さい。


「Form2」の配置したボタンをダブルクリックして、
「クリック時イベント」のコードを表示させておきます。

1
2
3
4
private void button1_Click(object sender, EventArgs e)
{
 
}

次に、
「Form2」デザインのイベントから
「FormClosing」をダブルクリックして、
「Form終了時イベント」のコードを表示させておきます。



1
2
3
4
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
 
}

準備が出来たので、
Form間でのデータ受け渡しの
いくつかのパターンを記載します。


●パターンA

「Form2」側で「Form1」のインスタンスを取得して、
「Form1」の持っているデータの取得や設定をしたいので、
以下のようにします。

Form1.cs(パターンA)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public partial class Form1 : Form
{
 
    //Form1インスタンス格納用
    private static Form1 _form1Instance;
 
    public Form1()
    {
        InitializeComponent();
        //Form1インスタンスを格納する
        _form1Instance = this;
    }
 
    //Form1インスタンスを設定、取得する。
    public static Form1 Form1Instance { get => _form1Instance; set => _form1Instance = value; }
    //テキストボックスへテキストを設定、取得する。
    public string TextBoxText { get => textBox1.Text; set => textBox1.Text = value; }
 
 
    private void button1_Click(object sender, EventArgs e)
    {
        using (var subForm = new Form2())
        {
            //Form2表示
            subForm.ShowDialog();
        }
    }
}
Form2.cs(パターンA)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public partial class Form2 : Form
 {
     //Form1インスタンス格納用
     private Form1 form1Instance;
 
     public Form2()
     {
 
         InitializeComponent();
 
         //Form1のインスタンスを取得
         form1Instance = Form1.Form1Instance;
         //Form1のテキストボックス文字列を
         //Form2のテキストボックス文字列へ設定
         textBox1.Text = form1Instance.TextBoxText;
 
     }
 
     private void button1_Click(object sender, EventArgs e)
     {
         this.Close();
     }
 
     private void Form2_FormClosing(object sender, FormClosingEventArgs e)
     {
         //Form2のテキストボックス文字列を
         //Form1のテキストボックス文字列へ設定
         form1Instance.TextBoxText = textBox1.Text;
     }
 }
これで実行してみて下さい。
Form間でデータの受け渡しができるハズです。

このパターンAの方法だと、
「Form1」に自身のインスタンスの格納用メンバを用意して、
それに対してstaticを適用しています。

1つの「Form1」しか同時に使用しない場合はこれで大丈夫ですが、
複数の「Form1」のインスタンスを同時に使用する場合、
インスタンスの格納用メンバがstaticの為、
クラス内でstatic部分が共有されてしまい、
うまく動きません。

ですが、
普通は同一Formを複数同時に使う事はないので、
これでも問題ありません。


●パターンB

「Form1」から「Form2」をnewする際に
「Form1」のインスタンスを「Form2」へ
引数として渡す事により、
「Form2」から
「Form1」の持っているデータの取得や設定をしたいので、
以下のようにします。

Form1.cs(パターンB)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public partial class Form1 : Form
{
 
    public Form1()
    {
        InitializeComponent();
    }
 
    //テキストボックスへテキストを設定、取得する。
    public string TextBoxText { get => textBox1.Text; set => textBox1.Text = value; }
 
    private void button1_Click(object sender, EventArgs e)
    {
        using (var subForm = new Form2(this))
        {
            //Form2表示
            subForm.ShowDialog();
        }
    }
}
Form2.cs(パターンB)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public partial class Form2 : Form
{
    //Form1インスタンス格納用
    private Form1 form1Instance;
 
    public Form2(Form1 form1Instance)
    {
 
        InitializeComponent();
 
        //Form1のインスタンスを取得
        this.form1Instance = form1Instance;
 
        //Form1のテキストボックス文字列を
        //Form2のテキストボックス文字列へ設定
        textBox1.Text = this.form1Instance.TextBoxText;
 
    }
 
    private void button1_Click(object sender, EventArgs e)
    {
        this.Close();
    }
 
    private void Form2_FormClosing(object sender, FormClosingEventArgs e)
    {
        //Form2のテキストボックス文字列を
        //Form1のテキストボックス文字列へ設定
        form1Instance.TextBoxText = textBox1.Text;
    }
}
パターンAと比べると、
「Form1」からstaticが無くなり、
いくらかすっきりしました。

Form間のデータ受け渡し内容がシンプルな物であれば、
このパターンを使用するのがよさそうです。

これなら複数Formのインスタンスを作らなくては
いけない場合でも問題無く動きそうです。


●パターンC

「Form2」側に自身でダイアログを生成して、
表示させる自家製メソッドをstaticで用意。
引数と戻り値にリストを使用する事により、
フォーム間でデータの受け渡しを行います。

「Form1」側は「Form2」へ渡したいデータをリスト化し、
「Form2」自家製メソッドを引数付きで呼びます。
「Form2」のフォーム表示後、戻り値のリストを取り出し、
「Form1」内で利用します。

Form1.cs(パターンC)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public partial class Form1 : Form
{
 
    public Form1()
    {
        InitializeComponent();
    }
 
    private void button1_Click(object sender, EventArgs e)
    {
 
        //Form2への受け渡し用配列を作成
        var sendList = new List<object>();
        sendList.Add((string)textBox1.Text);
 
        //Form2を表示して戻り値を受け取る。
        List<object> resultObjs = Form2.ShowForm2(sendList);
 
        //Form2から受け取ったテキストを戻す
        textBox1.Text = (string)resultObjs[0];
 
    }
}

Form2.cs(パターンC)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public partial class Form2 : Form
{
    //Form1から受け取ったオブジェクト配列
    private List<object> argObjs = new List<object>();
    //Form1へ返す戻り値用オブジェクト配列
    public List<object> resultObjs = new List<object>();
 
    //コンストラクタで
    //複数の様々な型をオブジェクト配列で受け取る。
    public Form2(List<object> argObjs)
    {
 
        InitializeComponent();
 
        //自身のメンバへ格納
        this.argObjs = argObjs;
 
        //Form1のテキストボックス文字列を
        //Form2のテキストボックス文字列へ設定
        textBox1.Text = (string)this.argObjs[0];
 
    }
 
    //Form2のインスタンス作成用自家製メソッド
    static public List<object> ShowForm2(List<object> argObjs)
    {
        //Form2を生成
        using (Form2 subForm=new Form2(argObjs))
        {
            subForm.ShowDialog();//表示
            //戻り値用オブジェクト配列を返す
            return subForm.resultObjs;
        }
    }
 
    private void button1_Click(object sender, EventArgs e)
    {
        this.Close();
    }
 
    private void Form2_FormClosing(object sender, FormClosingEventArgs e)
    {
        //Form2のテキストボックス文字列を
        //戻り値用オブジェクト配列へ代入
        resultObjs.Add(textBox1.Text);
    }
}

これは、
受け渡したいデータが増えても、
「Form1」側に無駄にpublicが増えず、
格納するデータの順番さえちゃんと管理できれば楽そうです。

「Form2」自身で自分のインスタンスの生成、表示をやってくれるので
「Form1」側から見たときに、使いやすそうです。



0 件のコメント:

コメントを投稿

↑Topへ