ComboBoxとDataGridViewComboBoxColumnを同期させる(その2)

昨日はリストクラスをそのままバインドしたが、これは現実的ではないので、画面の状態を表しているDTOとしてクラスを書き直してみた。先日のgenderリストはDTOのメンバであり、性別の2値を格納するリストだ。

public class GenderDTO : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private IList genders = new List();
    public GenderDTO()
        : base()
    {
        this.genders.Add(new GenderItem(0, "男"));
        this.genders.Add(new GenderItem(1, "女"));
    }
    public IList Genders
    {
        get { return this.genders; }
        set 
        { 
            if (this.genders != value)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("Genders"));
                this.genders = value; 
            }
        }
    }
}
public class GenderItem
{
    private int value;
    private string name;

    public GenderItem(int value, string name)
        : base()
    {
        this.value = value;
        this.name = name;
    }

    public int Value
    {
        get { return this.value; }
        set { this.value = value; }
    }
    public string Name
    {
        get { return this.name; }
        set { this.name = value; }
    }
}

両方向バインディングを実現するためにINotifyPropertyChangedインタフェースを実装している以外はプレーンでなんのへんてつも無い。
ビューであるFormには、このオブジェクトのインスタンスを必要に応じて生成するボタンを追加して、GenderDTOのインスタンスをBindingSourceを介してバインドするようにコードを変更した。

static void Main()
{
	Form1 form = new Form1();
	BindingSource source = new BindingSource();
	GenderDTO dto = new GenderDTO();
	source.Add(dto);
	BindingControls(source, form, dto);

	form.newbutton.Click +=
	    delegate(object sender, EventArgs e)
	    {
	        source.Add(new GenderDTO());
	    };

	Application.Run(form);
}
static void BindControls(BindingSource source, Form1 form, GenderDTO dto)
{
    form.gendersComboBox.DataBindings.Add(new Binding("DataSource", source, "Genders"));
    form.gendersComboBox.DisplayMember = "Name";
    form.gendersComboBox.ValueMember = "Value";
    
    form.genderDataGridView.Columns.Clear();
    form.genderDataGridView.AutoGenerateColumns = false;
    form.genderDataGridView.DataSource = source;
    DataGridViewComboBoxColumn column = new DataGridViewComboBoxColumn();
    column.CellTemplate = new GenderItemComboBoxCell();
    form.genderDataGridView.Columns.Add(column);
    column.DataPropertyName = "Genders";
    column.DataSource = dto.Genders;
    column.DisplayMember = "Name";
    column.ValueMember = "Value";
}

昨日、思い通りにならなかった点をもう一度整理してみよう。

  • 1 DataGridViewComboBoxColumn上のComboBoxにデータソースが表示されていない

GenderDTOのメンバであるGendersは、ComboBoxとDataGridViewComboBoxColumn上のComboBoxのデータソースとしてバインドされており、ComboBoxにはバインドされたGendersの内容が表示されるが、DataGridViewComboBoxColumnにはなぜか表示されていない。

  • 2 ComboBoxの変更がDataGridViewComboBoxColumnに反映されていない

互いに同じデータソースを指しているComboBoxとDataGridViewComboBoxColumnだが、ComboBoxの選択値を変更しても(SelectedIndexを変更しても)、DataGridViewComboBoxColumn上に変更が反映されない。

次のエントリでは、これらの問題をどのように解決したかを書こう。