DataGridView:コンボボックス列を表示し選択値を取得する方法(サンプルあり)

📋 目次(クリックで展開)

DataGridView で一覧を表示する際、特定の列をコンボボックス(ドロップダウン)にして、マスタデータから選択させたいケースは多くあると思います。また、ユーザーがコンボボックスで選択した値(設定した値)をプログラム側で取得する、というシナリオもよくあります。

今回は、DataGridView にコンボボックス列を追加する基本手順と、設定された値を確実に取得する方法について解説します。

コンボボックス列の基本設定と値の仕組み

DataGridView でコンボボックスを表示するには、DataGridViewComboBoxColumn クラスを使用します。

この列で選択された値を正しく取得するためには、まず以下の2つのプロパティの役割を理解しておく必要があります。

  • DisplayMember:画面のコンボボックス内に表示するプロパティ名(例:部署名「開発部」)
  • ValueMember:裏側のデータとして保持するプロパティ名(例:部署コード「D01」)

プログラムからセルの値を取得すると、画面に見えている文字列(DisplayMember)ではなく、ValueMember に指定した裏側の値(IDやコードなど)が取得できる仕組みになっています。

実装コード

以下は、社員一覧の DataGridView に対し、部署を選択するためのコンボボックス列を紐付け、ボタンがクリックされたタイミングで「現在選択されている行の部署コード(設定された値)」を正確に取得するサンプルコードです。

画面側の処理

Form1.cs
using System.ComponentModel;
using System.Windows.Forms;
namespace DataGridView_ComboBoxColumn
{
public partial class Form1 : Form
{
// 社員一覧のリスト
private BindingList<MemberModel> _members = new();
// コンボボックスの選択肢となる部署マスタのリスト
private List<DepartmentModel> _departments = new();
public Form1()
{
InitializeComponent();
InitializeDataGridView();
}
private void InitializeDataGridView()
{
// 1. 部署マスタ(選択肢)の準備
_departments.Add(new DepartmentModel("D01", "開発部"));
_departments.Add(new DepartmentModel("D02", "営業部"));
_departments.Add(new DepartmentModel("D03", "総務部"));
// 2. 初期データの登録
_members.Add(new MemberModel("M001", "山田 太郎", "D01"));
_members.Add(new MemberModel("M002", "佐藤 花子", "D02"));
// 3. 先にコンボボックス列を作成して DataGridView に追加する
var comboCol = new DataGridViewComboBoxColumn();
comboCol.DataPropertyName = nameof(MemberModel.DepartmentCode); // 社員モデルのバインド先
comboCol.HeaderText = "所属部署";
comboCol.DataSource = _departments; // 選択肢のデータ源
comboCol.ValueMember = nameof(DepartmentModel.Code); // 裏側の値(部署コード)
comboCol.DisplayMember = nameof(DepartmentModel.Name); // 画面に見せる文字(部署名)
dataGridView1.Columns.Add(comboCol);
// 4. その他の列を自動生成してデータソースを設定
dataGridView1.DataSource = _members;
dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
// 選択を変更した瞬間に値を確定させるイベント
dataGridView1.CurrentCellDirtyStateChanged += DataGridView1_CurrentCellDirtyStateChanged;
}
// セルの状態が「編集中」になった瞬間に呼び出されるイベント
private void DataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (dataGridView1.CurrentCell is DataGridViewComboBoxCell)
{
// まだセルにフォーカスが残っていても、強制的に編集を確定(コミット)させる
dataGridView1.EndEdit();
}
}
// 「設定された値を取得」ボタンのクリックイベント
private void btnGetValue_Click(object sender, EventArgs e)
{
if (dataGridView1.CurrentRow == null) return;
// 設定した値の取得
// パターンA:セルの Value プロパティから直接取得する
// (ValueMember に指定した "DepartmentCode" の値が取得できます)
string codeFromCell = dataGridView1.CurrentRow.Cells[0].Value?.ToString() ?? "";
// パターンB:バインド元のデータモデルから型安全に取得する(推奨)
if (dataGridView1.CurrentRow.DataBoundItem is MemberModel selectedMember)
{
string codeFromModel = selectedMember.DepartmentCode;
// どちらの方法でも、現在選択されている部署コード("D01" など)が確実に取得できます
MessageBox.Show($"セルから取得した部署コード: {codeFromCell}\n" +
$"モデルから取得した部署コード: {codeFromModel}");
}
}
}
}

データモデルクラス

MemberModel.cs
namespace DataGridView_ComboBoxColumn
{
// グリッドの行にバインドする社員モデル
public class MemberModel
{
public string Id { get; set; }
public string Name { get; set; }
public string DepartmentCode { get; set; } // コンボボックスの ValueMember と連動
public MemberModel(string id, string name, string departmentCode)
{
Id = id;
Name = name;
DepartmentCode = departmentCode;
}
}
}
DepartmentModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DataGridView_ComboBoxColumn
{
// コンボボックスの選択肢となる部署モデル
public class DepartmentModel
{
public string Code { get; set; }
public string Name { get; set; }
public DepartmentModel(string code, string name)
{
Code = code;
Name = name;
}
}
}

実行結果

行を選択した状態で、「データを取得」ボタンをクリックすると、コンボボックスが埋め込まれているセルの値(M001)と、コンボボックス列にバインドされているデータソースの値を、それぞれ取得しています。

サンプルアプリケーション

DataGridView_ComboBoxColumn.zip
※ サンプルアプリケーションは、.NET 9 をターゲットに作成しています。

選択直後にボタンを押したときに古い値が取れる問題の対策

「コンボボックスの値を変更した直後に、他のセルに移動せず画面下の「データ取得」ボタンを押すと、変更前の古い値が取得されてしまう」という現象は、DataGridView のコンボボックス実装におけるよくある問題です。

DataGridView の標準仕様では、ドロップダウンから項目を選んだだけではデータが確定せず、「そのセルからフォーカスが離れた瞬間」に初めて値が書き換わる(確定する)ようになっています。

これを防ぎ、「設定した値をその場で確実に取得する」状態を作るのが、サンプルコード内に記述した CurrentCellDirtyStateChanged イベントです。

項目がクリックされてセルの状態が「変更された(Dirty)」になった瞬間に、コード側から dataGridView1.EndEdit() を呼び出して強制的に編集を確定させることで、ユーザーがセルの中に留まったままボタンを押しても、最新の選択値を取得できるようになります。

注意点

コンボボックス列から正しく値が取得できない場合、プログラムのバグではなく、データ側の「型の不一致」が原因であるケースが多いです。

ValueMember と バインド先プロパティの「型」を一致させる

今回のサンプルでは、部署マスタの CodeValueMember)も、社員モデルの DepartmentCode(バインド先)も、どちらも string で統一しています。 もし、マスタのコードが int 型であるにもかかわらず、バインド先のプロパティが string 型になっていた場合、DataGridView 内部での型変換に失敗し、値が正常に取得できないだけでなく、画面に DataError イベントの警告ダイアログが表示されてしまう原因になります。必ず双方のデータ型を一致させてください。

まとめ

今回は、DataGridView にコンボボックス列を追加する方法と、選択された値を確実に取得するための実装パターンについて解説しました。

コンボボックス列から値を参照する際は、以下の2点を意識することが重要です。

  1. ValueMember に指定したプロパティの値(コードやID)が、セルの Value やバインド元モデルに書き込まれる。
  2. 選択直後の取得漏れを防ぐために、CurrentCellDirtyStateChanged イベントで即座に EndEdit() を行う。

今回の記事が、マスタ連動を伴う高度な業務アプリ画面を開発する際の参考になりましたら幸いです。


💬 コメント