DataGridViewに入力できるコンボボックスを1セルだけ作成する。
入力されたアイテムがコンボボックス内のリストになければ、コンボボックス内のリストの先頭に追加する。
これを実現するために、DataGridViewのEditingControlShowingイベントとCellValidatingイベントでいろいろする必要がある。
EditingControlShowingイベントは、編集用のコンボボックスが作成され表示される直前にコールされる。
DataGridViewの場合はDataGridViewComboBoxEditingControlが作成されるが、このコントロールのDropDownStyleをComboBoxStyle.DropDownに変更する。これでコンボボックスへの入力は可能となるが、入力した内容がリストに追加されない。
リストへの追加はCellValidatingイベントで行う。
CellValidatingイベントはセルがフォーカスを失う時にコールされる。
このとき、入力された文字列がコンボボックス内のリストにない場合は、リストに追加する必要がある。
さらに、最終セルの場合(例えば3×3のリストで右下のセル)は入力後のEnterキーでCellValidatingイベントが発生しない。これはカレントのセルが遷移しないため。これを解決するためにEnterキーのイベントでカレントセルを一度クリアし、再度設定してCellValidatingイベントを発生させる。
以下、サンプルソース。
// フォームのロードでDataGridViewを初期化
private void Form1_Load(object sender, EventArgs e)
{
// 列を追加
dataGridView1.Columns.Add("aaaa", "aaaa");
dataGridView1.Columns.Add("bbbb", "bbbb");
dataGridView1.Columns.Add("cccc", "cccc");
// 行を追加
dataGridView1.Rows.Add();
dataGridView1.Rows.Add();
dataGridView1.Rows.Add();
// DataGridView全体を編集可能にする
dataGridView1.ReadOnly = false;
// 3x3の一番右下のセルを入力できるコンボボックスにする。
dataGridView1[2, 2] = new DataGridViewComboBoxCell();
dataGridView1[2, 2].ReadOnly = false; // 編集可能に設定
// コンボボックスにアイテムを追加する
((DataGridViewComboBoxCell)dataGridView1[2, 2]).Items.Add("あああ");
((DataGridViewComboBoxCell)dataGridView1[2, 2]).Items.Add("いいい");
((DataGridViewComboBoxCell)dataGridView1[2, 2]).Items.Add("ううう");
((DataGridViewComboBoxCell)dataGridView1[2, 2]).Items.Add("えええ");
((DataGridViewComboBoxCell)dataGridView1[2, 2]).Items.Add("おおお");
}
// DataGridViewのEditingControlShowingイベントを処理する
private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
DataGridView dgv = (DataGridView)sender;
// コントロールがDataGridViewComboBoxEditingControlの場合
if (e.Control is DataGridViewComboBoxEditingControl)
{
// 該当位置のセルの場合
if ((dgv.CurrentCell.RowIndex == 2) && (dgv.CurrentCell.ColumnIndex == 2))
{
// DropDownStyleをドロップダウンに変更
((DataGridViewComboBoxEditingControl)e.Control).DropDownStyle = ComboBoxStyle.DropDown;
// Enrerキーイベントを捕まえるためのイベントを登録
((DataGridViewComboBoxEditingControl)e.Control).PreviewKeyDown += new PreviewKeyDownEventHandler(Form1_PreviewKeyDown);
}
}
}
// DataGridViewComboBoxEditingControlのキーイベントを処理する
void Form1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
// Enterキーの場合
if (e.KeyCode == Keys.Enter)
{
// カレントセルをバックアップ
DataGridViewCell curCell = ((DataGridViewComboBoxEditingControl)sender).EditingControlDataGridView.CurrentCell;
// カレントセルをクリア
((DataGridViewComboBoxEditingControl)sender).EditingControlDataGridView.CurrentCell = null;
// カレントセルを再設定(これでCellValidatingイベントが発行される)
((DataGridViewComboBoxEditingControl)sender).EditingControlDataGridView.CurrentCell = curCell;
}
}
// CellValidatingイベントを処理する
private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
DataGridView dgv = (DataGridView)sender;
// 該当位置のセルの場合
if ((dgv.CurrentCell.RowIndex == 2) && (dgv.CurrentCell.ColumnIndex == 2))
{
// コンボボックス内のリストを更新
UpdateCmbList(dgv.CurrentCell.ColumnIndex, dgv.CurrentCell.RowIndex, e.FormattedValue, ref this.dataGridView1);
}
}
// コンボボックス内のリストを更新する
private void UpdateCmbList(int colIndex, int rowIndex, object value, ref DataGridView dgv)
{
bool delete = false;
bool add = false;
// 値を文字列に変換
string formattedValue = string.Empty;
if (value != null)
{
formattedValue = value.ToString();
}
// リストの項目数が選択項目より多い場合は先頭の項目を削除
if (((DataGridViewComboBoxCell)dgv.Rows[rowIndex].Cells[colIndex]).Items.Count > 5)
{
// 先頭の項目が今回入力した文字列でない場合は削除を予約
// ここで削除すると、セルのValueをまだ変更していないので例外が発生する。
// セルのValueを変更後にリストから削除する。
if (((DataGridViewComboBoxCell)dgv.Rows[rowIndex].Cells[colIndex]).Items[0].ToString() != formattedValue)
{
delete = true;
}
}
// 値がリストに存在するか確認
if (((DataGridViewComboBoxCell)dgv.Rows[rowIndex].Cells[colIndex]).Items.Contains(formattedValue) != true)
{
// 存在しない場合は先頭に追加
((DataGridViewComboBoxCell)dgv.Rows[rowIndex].Cells[colIndex]).Items.Insert(0, formattedValue);
add = true;
}
// 一度コミットする(リストへの追加を有効にするため)
dgv.CommitEdit(DataGridViewDataErrorContexts.Commit);
// セルのValueを更新
((DataGridViewComboBoxCell)dgv.Rows[rowIndex].Cells[colIndex]).Value = formattedValue;
// リストから削除
if (delete == true)
{
int index = 0;
if (add == true)
{
index = 1;
}
((DataGridViewComboBoxCell)dgv.Rows[rowIndex].Cells[colIndex]).Items.RemoveAt(index);
}
// もう一度コミットする
dgv.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
