【C#】【Form】ComboBox ~ 複数コンボボックスを連動させるには ~

■ はじめに

複数コンボボックスを連動させることを考える
色々なスマートな方法があると思うが、オーソドックスに実装する

 * 地方-都道府県-市・区
  + 地方:関東、関西、東北、、、
  + 都道府県:東京、大阪、、、
  + 市・区:港区、横浜市、、、

■ 注意点

【1】データバインド時、 DisplayMemer, ValueMemberを事前に設定する
【2】TextChangedイベントで行う

【1】データバインド時、 DisplayMemer, ValueMemberを事前に設定する

https://netplanetes.wordpress.com/2010/04/20/comboboxforms-%E3%81%AE-datasource-%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%E3%81%A8%E3%81%8D%E3%81%AE%E6%B3%A8%E6%84%8F%E7%82%B9/
より抜粋
~~~~~~~~
DisplayMember, ValueMember をセットする前に DataSource にバインドすると、
SelectedIndexChanged イベントが起動されて
ComboBox.SelectedValue の値が想定した値(ValueMember) ではなく、
バインドしている現在選択されているオブジェクトそのものになってしまいます。
~~~~~~~~
 => これで例外になり落ちた

【2】TextChangedイベントで行う

SelectedIndexChanged イベント や SelectionChangeCommitted イベント だと
変更していなくても、イベント が走ってしまう

■ サンプル

using System;
using System.Data;
using System.Windows.Forms;

namespace SampleForm
{
  public partial class Form1 : Form
  {
    private DataTable dataTable;

    public Form1()
    {
      InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
      dataTable = new DataTable("Japan");

      dataTable.Columns.Add("area", typeof(string));
      dataTable.Columns.Add("prefecture", typeof(string));
      dataTable.Columns.Add("city", typeof(string));

      dataTable.Rows.Add("Kanto", "Tokyo", "Setagaya");
      dataTable.Rows.Add("Kanto", "Tokyo", "Shibuya");
      dataTable.Rows.Add("Kanto", "Tokyo", "Nakano");
      dataTable.Rows.Add("Kanto", "Kanagawa", "Yokohama");
      dataTable.Rows.Add("Kanto", "Kanagawa", "Kawasaki");
      dataTable.Rows.Add("Kanto", "Saitama", "Saitama");
      dataTable.Rows.Add("Kanto", "Saitama", "Fukaya");
      dataTable.Rows.Add("Kanto", "Saitama", "Koshigaya");
      dataTable.Rows.Add("Kanto", "Saitama", "Kawaguchi");
      dataTable.Rows.Add("Kyushu", "Fukuoka", "Fukuoka");
      dataTable.Rows.Add("Kyushu", "Nagasaki", "Nagasaki");
      dataTable.Rows.Add("Kyushu", "Kagoshima", "Kagoshima");

      var resultDataTableForArea = dataTable.DefaultView.ToTable(true, new string[] { "area" });
      this.comboBox1.DisplayMember = "area";
      this.comboBox1.ValueMember = "area";
      this.comboBox1.DataSource = resultDataTableForArea;
      this.comboBox1.SelectedIndex = 0;

      this.InitializePrefectureComboBox();

      this.InitializeCityComboBox();
    }

    private void InitializePrefectureComboBox()
    {
      var resultDataTableForPrefecture = dataTable.AsEnumerable().Where(
        row => row.Field<string>("area") == this.comboBox1.SelectedValue.ToString())
        .AsDataView().ToTable(true, new string[] { "area", "prefecture" });
      this.comboBox2.DisplayMember = "prefecture";
      this.comboBox2.ValueMember = "prefecture";
      this.comboBox2.DataSource = resultDataTableForPrefecture;
      this.comboBox2.SelectedIndex = 0;
    }

    private void InitializeCityComboBox()
    {
      var resultDataTableForCity = dataTable.AsEnumerable().Where(
        row => row.Field<string>("area") == this.comboBox1.SelectedValue.ToString() &&
        row.Field<string>("prefecture") == this.comboBox2.SelectedValue.ToString())
        .AsDataView().ToTable(true, new string[] { "area", "prefecture", "city" });
      this.comboBox3.DisplayMember = "city";
      this.comboBox3.ValueMember = "city";
      this.comboBox3.DataSource = resultDataTableForCity;
      this.comboBox3.SelectedIndex = 0;
    }

    private void comboBox1_TextChanged(object sender, EventArgs e)
    {
      this.InitializePrefectureComboBox();

      this.InitializeCityComboBox();
    }

    private void comboBox2_TextChanged(object sender, EventArgs e)
    {
      this.InitializeCityComboBox();
    }
  }
}


関連記事

Windows Form ~ 目次 ~

https://blogs.yahoo.co.jp/dk521123/8054245.html

コンボボックス関連

ComboBox ~ 基本編 ~
https://blogs.yahoo.co.jp/dk521123/30294576.html
ComboBox ~ あれこれ編 ~
https://blogs.yahoo.co.jp/dk521123/20513549.html

その他

DataTable ~ DISTINCT / 重複した値を省くには... ~
https://blogs.yahoo.co.jp/dk521123/14321146.html
DataTable ~ DataTable で Linq する ~
https://blogs.yahoo.co.jp/dk521123/37976709.html