Windows Forms のデータバインディング


# Windows Forms のデータバインディング

WPF では当然のように使用されるデータバインディングですが、Forms でもデータをバインドできます。
そこで、簡単なプログラムを作成してみます。

作成するプログラムは、名前を入力しボタンをクリックしたら、入力された名前をメッセージボックスに出力するだけのプログラムです。

## モデルの作成

バインドするモデルを作成します。
今回は、Name プロパティを持つクラスを Form クラスの内部に作成してみます。入れ子にする意味はありません。
Name プロパティの値が変わったときに画面の表示も更新したいので、INotifyPropertyChanged も実装します。

[Form1.vb](https://gist.github.com/peace2048/9b4f21fbbdcb46760a4f/6c59a9e7205e2c6db0cd5a724f0bfa1a3688a15a#file-form1-vb)

```vbnet

Imports System.ComponentModel

Public Class Form1

    Public Class Model
        Implements INotifyPropertyChanged

        Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

        Private _name As String
        Public Property Name() As String
            Get
                Return _name
            End Get
            Set(ByVal value As String)
                _name = value
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(NameOf(Name)))
            End Set
        End Property
    End Class

End Class
```

## バインドの設定

フォームデザイナでバインドを設定する場合は、モデルクラスがコンパイル済みでないと参照できないので、一度ソリューションをコンパイルします。

フォームデザイナでバインド先のテキストボックスを選択し、プロパティの(DataBindings) Text のドロップダウンを開き、Add Project Data Source を選択します。
Data Source Type に Object を選択し、Form1.Model を選択して完了させます。
今回は Model クラスにプロパティが一つなので、自動的に Name プロパティにバインドされますが、プロパティが複数存在する場合は、バインドするプロパティを選択します。

![vs](https://gist.github.com/peace2048/9b4f21fbbdcb46760a4f/raw/b3f5ab528cb16d5134fb53bc06c2fd2e70349e30/vs1.png)
![vs](https://gist.github.com/peace2048/9b4f21fbbdcb46760a4f/raw/0be7e7c7f94a329064032136e52f6974a3b243b5/vs2.png)

## モデルインスタンスの設定

この状態で実行しても、モデルがインスタンス化されませんので、プログラムでインスタンス化とDataSourceへの設定を行います。
モデルは、バインド以外でも使用しますので、メンバ変数に保存するようにします。
取りあえず、Form1 のコンストラクタにデザイナで作成されたModelBindingSource.DataSource にモデルインスタンスを代入します。

Click ボタンのイベントハンドラにモデルインスタンスの Name を MessageBox で表示するようにすると、テキストボックスで入力された値がモデルインスタンスの Name プロパティに自動で設定されますので入力した値がメッセージボックスで表示されます。

Clear ボタンのイベントハンドラでモデルインスタンスの Name プロパティに空文字列を設定すると、PropertyChangedイベントが発生し、テキストボックスの表示も自動で更新されます。

最終的な [Form1.vb](https://gist.github.com/peace2048/9b4f21fbbdcb46760a4f#file-form1-vb)

```vbnet

Imports System.ComponentModel

Public Class Form1

    Private _model As New Model()

    Public Sub New()

        InitializeComponent()

        ModelBindingSource.DataSource = _model

    End Sub

    Public Class Model
        Implements INotifyPropertyChanged

        Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

        Private _name As String
        Public Property Name() As String
            Get
                Return _name
            End Get
            Set(ByVal value As String)
                _name = value
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(NameOf(Name)))
            End Set
        End Property
    End Class

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        MessageBox.Show(_model.Name)
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        _model.Name = String.Empty
    End Sub

End Class
```

## コードによるバインディング

フォームデザイナでバインドすると、モデルのプロパティ名を変更したときにリファクタリングされません。
NameOf演算子を使えば文字列リテラルを無くせますので、リファクタリング対象になります。

```vbnet

TextBox1.DataBindings.Add(New Binding(NameOf(TextBox1.Text), _model, NameOf(_model.Name))
```

ちょっと長めになりますが、スニペットにすれば大丈夫でしょう。