フォーム間でデータや値の受け渡しをする - C#

C#でフォーム間でデータの受け渡しをする方法を紹介します。

概要

フォーム間でデータの受け渡しをするコードを紹介します。いくつかの方法があります。
  • 共有先のフォームのプロパティ、メンバ変数に値を設定する、またはメソッドを呼び出す
  • フォームオブジェクトを共有先のフォームから参照できるようにする
  • Progamクラスのメンバ変数を利用する
  • 共有メモリ、ファイルで値を渡す
  • Dependency Injection (DI)で値を渡す

相手のフォームのプロパティ、メンバ変数に値を設定する、またはメソッドを呼び出す

フォーム間でデータの交換をする場合によく使われる方法です。 送信側のフォームから受信側のフォームのメソッドを呼び出すか、プロパティに代入します。 サブフォーム側から、メインフォームへの呼び出しが無ければ、依存関係は低くできます。

一方でサブフォームから呼び出し元のフォームに値を設定したり、フォームのクラスのメソッドを実行する場合には、 サブフォームのメンバ変数に呼び出し元のフォームのオブジェクトを代入するか、サブフォームのOwnerプロパティに呼び出し元のフォームを設定して、サブフォームから メインフォームのオブジェクトを参照できるようにする必要があります。
サブフォームから、メインフォームへの参照を追加すると、依存関係は高くなってしまいます。

フォームオブジェクトを共有先のフォームから参照できるようにする

先の方法と似ていますが、値を設定するのではなく、フォームオブジェクトを参照できるようにする方法です。
Publicで定義されているもののみが操作できるため、アクセス識別子を厳しく設定すれば、依存関係は比較的弱くできるかと思われます。

Progamクラスのメンバ変数を利用する

Programクラスにメンバ変数を宣言して、その変数を共有する方法です。
Programクラスの変数がグローバル変数的な意味合いになってしまうため、依存関係は強くなってしまいます。

共有メモリ、ファイルを利用する

共有メモリやファイルを利用する方法です。
ファイルを利用する方法はこの記事では紹介しません。
共有メモリについてはこちらの記事を参照してください。

Dependency Injection (DI)で値を渡す

Dependency Injection (DI)を利用する方法です。この記事では紹介しません。
詳しくはこちらの記事を参照してください。

比較

それぞれの方式の特徴
方式コードの記述量値の一意性サブフォームからメインフォームの呼び出し相互依存度
プロパティ、メンバ変数に値を設定
フォームオブジェクトを共有
Progamクラス
共有メモリ、ファイルを利用
Dependency Injection (DI)

プログラム: プロパティ、メンバ変数に値を設定する方法

UI

下図のUIを作成します。

FormMain

ボタンとラベルを配置します。

FormSub

メインのフォームと同様に、ボタンとラベルを配置します。

コード

以下のコードを記述します。
FormMain.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace MultiFormDataTransfer
{
  public partial class FormMain : Form
  {
    private string receiveData ="";
    FormSub fs;

    public FormMain()
    {
      InitializeComponent();
      fs = new FormSub();
      fs.formMain = this;
    }

    private void button1_Click(object sender, EventArgs e)
    {
      fs.SendData = "Penguin";
    }

    public string ReceiveData
    {
      set
      {
        receiveData = value;
        label1.Text = receiveData;
      }
      get
      {
        return receiveData;
      }
    }

    private void FormMain_Shown(object sender, EventArgs e)
    {
      fs.Show();

    }
  }
}
FormSub.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace MultiFormDataTransfer
{
  public partial class FormSub : Form
  {
    private string sendData="";
    public FormMain formMain;

    public FormSub()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      if (formMain != null) {
        formMain.ReceiveData = "Duck";
      }
    }

    public string SendData
    {
      set
      {
        sendData = value;
        label1.Text = sendData;
      }
      get
      {
        return sendData;
      }
    }
  }
}

解説

メインフォームが表示されたタイミングで、サブフォームを表示します。 作成したサブフォームのインスタンスはメインフォームに保持します。
サブフォームからメインフォームに値を戻す際に、メインフォームのオブジェクトを参照する必要があるため、Ownerプロパティにメインフォームのオブジェクトを設定します。
    public FormMain()
    {
      InitializeComponent();
      fs = new FormSub();
      fs.Owner = this;
    }

メインフォームのボタンがクリックされると、サブフォームのクラスのSendDataプロパティに値を代入してサブフォームに値を渡します。
    private void button1_Click(object sender, EventArgs e)
    {
      fs.SendData = "Penguin";
    }

サブフォームのSendDataプロパティでは、値をメンバ変数に格納後、ラベルに受け取った値を表示します。
    public string SendData
    {
      set
      {
        sendData = value;
        label1.Text = sendData;
      }
      get
      {
        return sendData;
      }
    }

サブフォームのボタンがクリックされた場合は、Ownerプロパティからメインフォームのオブジェクトを取得し、メインフォームのプロパティに値を代入します。
    private void button1_Click(object sender, EventArgs e)
    {
      FormMain fm = (FormMain)this.Owner;
      if (fm != null) {
        fm.ReceiveData = "Duck";
      }
    }
フォーム間で情報を交換する場合、メインフォームからサブフォームへの受け渡しの場合はメインフォームではサブフォームのインスタンス変数を保持しているため、 サブフォームのpublicメンバ変数を用いたり、プロパティを用いて情報を交換できます。 一方サブフォームからメインフォームへ情報を受け渡す場合、サブフォームはメインフォームのインスタンスを保持していないため、 サブフォームの呼び出し時にメインフォームのインスタンスをサブフォームの変数に渡すか、もしくはOwnerプロパティを設定し、 サブフォームにメインフォームのインスタンスを伝える必要があります。

実行結果

プロジェクトを実行します。フォームが2つ表示されます。



メインのフォームの[button1]をクリックします。サブのフォームのラベルに"Penguin"の文字列が表示されます。メインのフォームで代入した値がサブフォームに反映されています。


サブフォームの[button1]ボタンをクリックします。メインフォームのラベルに"Duck"の文字列が表示されます。サブのフォームで代入した値がメインフォームのラベルに反映されます。

補足 : Ownerプロパティを用いる例

先のコードと同様の処理ですが、Ownerプロパティを用いた場合の実装コードは次の通りです。
以下のコードを記述します。
FormMain.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace MultiFormDataTransfer
{
  public partial class FormMain : Form
  {
    private string receiveData ="";
    FormSub fs;

    public FormMain()
    {
      InitializeComponent();
      fs = new FormSub();
      fs.Owner = this;
    }

    private void button1_Click(object sender, EventArgs e)
    {
      fs.SendData = "Penguin";
    }

    public string ReceiveData
    {
      set
      {
        receiveData = value;
        label1.Text = receiveData;
      }
      get
      {
        return receiveData;
      }
    }

    private void FormMain_Shown(object sender, EventArgs e)
    {
      fs.Show();

    }
  }
}
FormSub.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace MultiFormDataTransfer
{
  public partial class FormSub : Form
  {
    private string sendData="";
    public FormMain formMain;

    public FormSub()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      FormMain fm = (FormMain)this.Owner;
      if (fm != null) {
        fm.ReceiveData = "Duck";
      }
    }

    public string SendData
    {
      set
      {
        sendData = value;
        label1.Text = sendData;
      }
      get
      {
        return sendData;
      }
    }
  }
}

解説

メインフォームが表示されたタイミングで、サブフォームを表示します。 作成したサブフォームのインスタンスはメインフォームに保持します。
サブフォームからメインフォームに値を戻す際に、メインフォームのオブジェクトを参照する必要があるため、Ownerプロパティにメインフォームのオブジェクトを設定します。
    public FormMain()
    {
      InitializeComponent();
      fs = new FormSub();
      fs.Owner = this;
    }

メインフォームのボタンがクリックされると、サブフォームのクラスのSendDataプロパティに値を代入してサブフォームに値を渡します。
    private void button1_Click(object sender, EventArgs e)
    {
      fs.SendData = "Penguin";
    }

サブフォームのSendDataプロパティでは、値をメンバ変数に格納後、ラベルに受け取った値を表示します。
    public string SendData
    {
      set
      {
        sendData = value;
        label1.Text = sendData;
      }
      get
      {
        return sendData;
      }
    }

サブフォームのボタンがクリックされた場合は、Ownerプロパティからメインフォームのオブジェクトを取得し、メインフォームのプロパティに値を代入します。
    private void button1_Click(object sender, EventArgs e)
    {
      FormMain fm = (FormMain)this.Owner;
      if (fm != null) {
        fm.ReceiveData = "Duck";
      }
    }

プログラム: フォームのオブジェクトを参照する方法

先の方法と仕組みは同じです。値をプロパティやメンバ変数に設定せずに、フォームのオブジェクトを参照できる状態にします。

UI

下図のUIを作成します。

FormMain

ボタンとラベルを配置します。

FormSub

メインのフォームと同様に、ボタンとラベルを配置します。

コード

下記のコードを記述します。
FormMain.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MultiFormDataTransferRO
{
  public partial class FormMain : Form
  {
    private FormSub fs;
    public string DataString { get; set; }

    public FormMain()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      DataString = "かるがもサブレ";
      if (fs != null) {
        fs.UpdateData();
      }
    }

    private void FormMain_Shown(object sender, EventArgs e)
    {
      fs = new FormSub();
      fs.Show();
      fs.formMain = this;
    }

    public void UpdateData()
    {
      label1.Text = DataString;
    }
  }
}
FormSub.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MultiFormDataTransferRO
{
  public partial class FormSub : Form
  {
    public FormMain formMain { get;  set; }
    
    public FormSub()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      if (formMain != null) {
        formMain.DataString = "しろくまアイス";
        formMain.UpdateData();
      }
    }

    public void UpdateData()
    {
      if (formMain != null) {
        label1.Text = formMain.DataString;
      }
    }
  }
}

解説

メインのフォームのクラスのみにプロパティ(DataString)を宣言します。
   public string DataString { get; set; }

メインフォームが表示された直後にサブフォームを表示します。サブフォームからメインフォームにアクセスできるよう、 サブフォームの formMain プロパティにメインフォームのオブジェクトを代入します。
    private void FormMain_Shown(object sender, EventArgs e)
    {
      fs = new FormSub();
      fs.Show();
      fs.formMain = this;
    }

ボタンのクリックで値を自分のオブジェクトのプロパティ(DataString)に代入します。
代入後にサブフォームのUpdateData()メソッドを呼び出して値をラベルの表示に反映します。
    private void button1_Click(object sender, EventArgs e)
    {
      DataString = "かるがもサブレ";
      if (fs != null) {
        fs.UpdateData();
      }
    }

UpdateData()イベントでメインフォームのDataStringプロパティに代入されている値をラベルに表示します。
    public void UpdateData()
    {
      if (formMain != null) {
        label1.Text = formMain.DataString;
      }
    }

サブフォームからメインフォームへの値の渡し方は、サブフォームからメインフォームのオブジェクトを参照できるため、 メインフォームのオブジェクトの DataString プロパティに代入して値を渡します。
代入後にメインフォームのUpdateData()メソッドを呼び出して値をラベルの表示に反映します。
    private void button1_Click(object sender, EventArgs e)
    {
      if (formMain != null) {
        formMain.DataString = "しろくまアイス";
        formMain.UpdateData();
      }
    }

UpdateData()イベントでDataStringプロパティに代入されている値をラベルに表示します。
    public void UpdateData()
    {
      label1.Text = DataString;
    }

実行結果

プロジェクトを実行します。2つのフォームが表示されます。



メインフォームの[button1]ボタンをクリックします。サブフォームのラベルに「かるがもサブレ」の文字列が表示されます。 メインフォームのコードで代入した値がサブフォームのラベルに反映されます。


サブフォームの[button1]ボタンをクリックします。メインフォームのラベルに「しろくまアイス」の文字列が表示されます。 サブフォームのコードで代入した値がメインフォームのラベルに反映されます。

プログラム: Program クラスのメンバ変数を利用する方法

値の受け渡しのみをする場合には、Programクラスのメンバ変数を利用する方法もあります。

UI

下図のフォームを作成します。
メインのフォームにはボタンとラベルを配置します。


サブのフォームにもラベルとボタンを配置します。

コード

下記のコードを記述します。
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MultiFormDataTransferPC
{
  static class Program
  {
    static public string TransferText;

    /// <summary>
    ///  The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
      Application.SetHighDpiMode(HighDpiMode.SystemAware);
      Application.EnableVisualStyles();
      Application.SetCompatibleTextRenderingDefault(false);
      Application.Run(new FormMain());
    }
  }
}
FormMain.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MultiFormDataTransferPC
{
  public partial class FormMain : Form
  {
    public FormMain()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      Program.TransferText = "ぺんぎんクッキー";
      FormSub fs = new FormSub();
      fs.ShowDialog(this);

      label1.Text = Program.TransferText;
    }
  }
}

FormSub.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MultiFormDataTransferPC
{
  public partial class FormSub : Form
  {
    public FormSub()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      Program.TransferText = "らくだキャラメル";
      DialogResult = DialogResult.OK;
    }

    private void FormSub_Shown(object sender, EventArgs e)
    {
      label1.Text = Program.TransferText;
    }
  }
}

解説

Programクラスにメンバ変数TransferTextを宣言します。
  static class Program
  {
    static public string TransferText;

    /* 中略 */
  }

FormMain の[button1]をクリックすると下記のコードを実行します。Programクラスの TransferText 変数に受け渡す値を代入します。 代入後に別のフォーム FormSub のインスタンスを作成しフォームを表示します。
サブのフォームはモーダルで表示します。コードの詳細はこちらの記事を参照してください。
    private void button1_Click(object sender, EventArgs e)
    {
      Program.TransferText = "ぺんぎんクッキー";
      FormSub fs = new FormSub();
      fs.ShowDialog(this);

      label1.Text = Program.TransferText;
    }

FormSubではフォーム表示後に、Programクラスの TransferText 変数の値をフォームのラベルに表示します。
    private void FormSub_Shown(object sender, EventArgs e)
    {
      label1.Text = Program.TransferText;
    }

FormSubのボタンをクリックすると、Programクラスの TransferText 変数の値を変更し、DialogResultに値を設定してフォームを閉じます。
    private void button1_Click(object sender, EventArgs e)
    {
      Program.TransferText = "らくだキャラメル";
      DialogResult = DialogResult.OK;
    }

実行結果

プロジェクトを実行します。メインのフォーム(FormMain)が表示されます。


フォームの[button1]をクリックします。サブフォームが表示され、サブフォームのラベルにメインのフォームで設定した「ぺんぎんクッキー」の文字列が表示されます。 メインフォームの値をサブフォームに渡すことができました。
サブフォーム(FormSub)の[Close]ボタンをクリックします。


ボタンをクリックすると、サブフォームが閉じ、メインフォームのラベルにサブフォームで設定した「らくだキャラメル」の文字列が表示されます。
サブフォームの値をメインフォームで参照できました。

著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
掲載日: 2012-04-24
改訂日: 2021-08-15
iPentec all rights reserverd.