はじめに
コンボボックスを「文字列の並び」から一歩進めて、データ付きリストとして扱う鍵が
DataSource・DisplayMember・ValueMemberの3つです。
画面に見せる値(表示名)と、内部で扱う値(ID等)を分離でき、業務アプリで必須の知識になります。
各プロパティの役割
| プロパティ | 意味 | 例(都市マスタ) |
|---|---|---|
DataSource |
バインド元(配列・List<T>・DataTable・BindingSource)を指定 | List<City> / DataTable |
DisplayMember |
画面に表示するプロパティ名(列名) | "Name" → 「東京」 |
ValueMember |
内部的に扱う値のプロパティ名(列名) | "Id" → 1 |
💡 ポイント: ユーザーが「東京」を選んでも、アプリは
SelectedValue から Id=1 を扱えます。表示と内部値を綺麗に分離できます。
List<T> を使った基本例(最もシンプル)
public class City
{
public int Id { get; set; }
public string Name { get; set; }
}
var cities = new List<City>
{
new City { Id = 1, Name = "東京" },
new City { Id = 2, Name = "大阪" },
new City { Id = 3, Name = "名古屋" },
new City { Id = 4, Name = "福岡" },
};
comboBox1.DataSource = cities;
comboBox1.DisplayMember = "Name"; // 表示
comboBox1.ValueMember = "Id"; // 内部値
// 既定選択(ID=2 → 大阪)
comboBox1.SelectedValue = 2;
// 取得:ユーザーが選んだIDと表示名
int id = (int)comboBox1.SelectedValue;
string name = comboBox1.Text; // または ((City)comboBox1.SelectedItem).Name
DataTable を使った例(DB連携の定番)
var dt = new DataTable();
dt.Columns.Add("Id", typeof(int));
dt.Columns.Add("Name", typeof(string));
dt.Rows.Add(1, "営業部");
dt.Rows.Add(2, "開発部");
dt.Rows.Add(3, "総務部");
comboBoxDept.DataSource = dt;
comboBoxDept.DisplayMember = "Name";
comboBoxDept.ValueMember = "Id";
comboBoxDept.SelectedValue = 3; // 総務部を選択
int selectedDeptId = (int)comboBoxDept.SelectedValue;
BindingSource を使う(並べ替え・フィルタが楽)
var bs = new BindingSource();
bs.DataSource = cities; // List<City> や DataTable を設定
// DataTableの場合は bs.Sort / bs.Filter が使える
// 例: bs.Sort = "Name ASC";
comboBox1.DataSource = bs;
comboBox1.DisplayMember = "Name";
comboBox1.ValueMember = "Id";
🔁 データの差し替え・再読込 は BindingSource 経由がシンプル。
bs.DataSource = 新しいリスト; とするだけで UI が更新されます。
SelectedValue と SelectedItem の関係
- SelectedValue …
ValueMemberで指定した値(ID等)。保存・検索に最適。 - SelectedItem … 選択されたオブジェクト(行)。必要に応じてプロパティへアクセス。
- Text … 表示テキスト(=
DisplayMember)。
// 例:選択をIDで制御
comboBox1.SelectedValue = 4; // ID=4に対応する行が選択される
int id = (int)comboBox1.SelectedValue;
var row = comboBox1.SelectedItem; // City or DataRowView など
string display = comboBox1.Text; // 表示名
依存(カスケード)コンボボックスの基本パターン
「都道府県 → 市区町村」のように、親の選択で子の候補を絞る例:
// 親:都道府県
comboPref.DataSource = prefs; // List<Pref> { Id, Name }
comboPref.DisplayMember = "Name";
comboPref.ValueMember = "Id";
// 子:市区町村(BindingSourceで差し替え)
var bsCity = new BindingSource();
comboCity.DataSource = bsCity;
comboCity.DisplayMember = "Name";
comboCity.ValueMember = "Id";
comboPref.SelectedValueChanged += (_, __) =>
{
int prefId = (int)comboPref.SelectedValue;
var citiesInPref = allCities.Where(c => c.PrefId == prefId).ToList();
bsCity.DataSource = citiesInPref;
comboCity.SelectedIndex = citiesInPref.Count > 0 ? 0 : -1;
};
よくある落とし穴と対策
- DisplayMember / ValueMember の名前が間違っている:存在するプロパティ(列)名を設定。先に DataSource を設定し、その後に Member を設定すると安全。
- SelectedValue の型不一致:
intなのに"1"を代入する等は選択されません。型を合わせる。 - 表示順を並べ替えたい:DataTable + BindingSource の
Sort、または List をOrderByしてから DataSource に設定。 - Items と DataSource の併用:同時使用は不可。バインド中は
Items.Add()せず、元データを更新して再バインド。 - DropDownStyle=DropDownList での入力:自由入力不可。検索性は
AutoCompleteMode/Sourceで補う。
便利レシピ集
表示列は同じだが、内部値だけ変えたい
comboBox.DisplayMember = "Name";
comboBox.ValueMember = "Code"; // 例: "TOKYO" / "OSAKA"
列名が取りづらい匿名型でもOK
comboBox.DataSource = new[]
{
new { Id = 1, Name = "小計" },
new { Id = 2, Name = "消費税" },
new { Id = 3, Name = "合計" }
};
comboBox.DisplayMember = "Name";
comboBox.ValueMember = "Id";
前回選んだIDを復元
int lastId = Properties.Settings.Default.LastCityId;
comboBox1.SelectedValue = lastId;
まとめ
DataSourceで一覧の元データを渡し、DisplayMemberとValueMemberで見せ方と内部値を分離する。- 選択制御・保存・検索は
SelectedValueを中心に。 - 更新や並べ替えは
BindingSourceを介すと管理が楽。 - 型・プロパティ名・設定順序のミスが定番。まずは DataSource → Member の順で堅く組む。
Please follow and like us:

コメント