WinForms での、フォーム間でのデータの受け渡し方法

GUIを勉強し始めた頃に悩んだので、記録としてここに残します。

######方法① サブフォームから、メインフォームの公開プロパティに値をセットする。
この場合、サブフォームがメインフォームのpublicプロパティにアクセスする必要があるので、
サブフォームがメインフォームへの参照を持つ必要があります。
※サブフォームにpublicプロパティを作って、メインフォームがアクセスしても同じ。

```C#
public class MainForm : Form
{
    public string PublicProperty { get; set; }

    public void ShowSubForm()
    {
        var form = new SubForm()
        {
            ParentForm = this;
        };
        form.Show();
    }
}

public class SubForm : Form
{
    public Form ParentForm { get; set; }

    private void SetValueMethod()
    {
        ParentForm.PublicProperty = "テキスト";
    }
}
```
---

#####方法② データ受け渡し用のクラスを介して受け渡しする。
この方法なら、メインフォームとサブフォームが互いに参照することなく、データを受け渡し出来ます。

```C#
public static class DataClass
{
    public static string StringValue { get; set; }
}

public class MainForm : Form
{
    private string PrivateStringProperty { get; set; }

    public void GetValueMethod()
    {
        PrivateStringProperty = DataClass.StringValue;
    }
}

public class SubForm : Form
{
    public void SetValue()
    {
        DataClass.StringValue = "テキスト";
    }
}
```
---
#####方法③ イベントを使って渡す。
イベントを使う方法は、方法④ イベントを使って、DBを仲介してデータを受け渡しする時に便利。

```C#
public class MainForm : Form
{
    private string PrivateStringProperty { get; set; }

    public void ShowSubForm()
    {
        var form = new SubForm()
        {
            ParentForm = this;
        };
        form.DataPassEvent += SubForm_DataPassEvnet;
        form.Show();
    }

    private void SubForm_DataPassEvnet(object sender, DataPassEventArgs e)
    {
        PrivateStringProperty = e.StringData;
    }
}

public class SubForm : Form
{
    public delegate void DataEventHandler(DataPassEventArgs e);
    //このイベントをメインフォームでListenする。
    public event DataEventHandler DataPassEvent;

    private string StringDate;

    public void SetValue()
    {
        //ここでデータを加工したりする処理をして・・・
        //空白でない時だけ、イベントを起こしたりも出来る。
        if(!string.IsNullOrWhiteSpace(StringDate))
        {
            DataPassEvent?.Invoke(new DataPassEventArgs(StringData));
        }
    }
}

public class DataPassEventArgs : EventArgs
{
    public string StringData { get; set; }

    public DataPassEventArgs(string data)
    {
        StringData = data;
    }
}

```
---
#####方法④ イベントを使って、DBを仲介してデータを受け渡しする。
①サブフォームでDB更新 → ②DB更新した事をイベントとして通知 → ③メインフォームがDBのデータを参照
という流れ。
今回の場合は、データはDBにあるので、独自のEventArgsで渡す必要はありません。
必要であれば、更新したレコードの主キー等、渡す必要があるデータを渡すEventArgsを作ります。

```C#
public class MainForm : Form
{
    public void ShowSubForm()
    {
        var form = new SubForm();
        form.DatabaseUpdateCompleted += SubForm_DatabaseUpdateCompleted;
        form.Show();
    }

    private void SubForm_DatabaseUpdateCompleted(object sender, EventArgs e)
    {
        //データベースからデータを取得する処理。
    }
}

public class SubForm : Form
{
    public event EventHandler DatabaseUpdateCompleted;

    public void UpdateDatabase()
    {
        //ここでデータベースにレコードをInsertしたりUpdateしたりして・・・
        //その後、イベント起動。
        DatabaseUpdateCompleted?.Invoke(null, new EventArgs());
    }
}
```
####方法⑤ データ受け渡し用クラスで、データ変更イベントを起動して他のフォームに変更を通知する。
①サブフォームでDataClassのデータ更新 → ②DataClassがデータ変更イベントを起動 → ③イベントをListenしているメインフォームがデータを受け取る。
という流れ。

```C#
namespace Test
{
    public class MainForm : Form
    {
        static void Main(string[] args)
        {
            Application.Run(new MainForm());
        }

        public MainForm()
        {
            //データ管理用クラスの、データ変更イベントをListenする。
            DataClass.DataPassEvent += DataClass_DataPassEvent;

            //サブフォーム内に実装した、データを変更するメソッドを呼び出す。
            //下記メソッドはどのクラスから呼び出してもいいが、今回は2つしかクラスがないので、このクラスで呼び出す。
            new SubForm().Method();
        }

        private static void DataClass_DataPassEvent(DataChangeEventArgs e)
        {
            //データ変更前後の値を表示する。
            //メッセージBOXは4回表示され、表示結果は以下
            //------------------------------------------
            //①変更前は で 変更後は あいうえお
            //②変更前は あいうえお で 変更後は かきくけこ
            //③変更前は かきくけこ で 変更後は さしすせそ
            //④変更前は さしすせそ で 変更後は たちつてと
            //------------------------------------------
            MessageBox.Show($"変更前は { e.OldStringData } で 変更後は { e.NewStringData } ");
        }
    }

    public class SubForm : Form
    {
        //データ管理用クラスのデータを変更する。
        public void Method()
        {
            DataClass.StringValue = "あいうえお";
            DataClass.StringValue = "かきくけこ";
            DataClass.StringValue = "さしすせそ";
            DataClass.StringValue = "たちつてと";
        }
    }

    //データ管理用クラス
    public static class DataClass
    {
        public delegate void DataEventHandler(DataChangeEventArgs e);
        //このイベントをメインフォームとサブフォームでListenする。
        public static event DataEventHandler DataPassEvent;

        private static string oldValue;
        private static string newValue;

        public static string StringValue
        {
            get { return newValue; }
            set
            {
                //データ変更前後の値が違っていれば・・・
                if (oldValue != value)
                {
                    //元々あった値をoldValueに退避
                    oldValue = newValue;
                    //newValueにセットし・・・
                    newValue = value;
                    //データ変更イベントを起動する。
                    DataPassEvent?.Invoke(new DataChangeEventArgs(oldValue, newValue));
                };
            }
        }
    }

    //変更前後の値を渡す為のEventArgs
    public class DataChangeEventArgs : EventArgs
    {
        public string OldStringData { get; set; }
        public string NewStringData { get; set; }

        public DataChangeEventArgs(string oldData, string newData)
        {
            OldStringData = oldData;
            NewStringData = newData;
        }
    }
}
```