通过在单元格中键入,将项目动态添加到 DataGridView ComboBox 列
Dynamically add item to DataGridView ComboBox Column by typing in the cell
我有一个 DataGridView
,它有一个 ComboBox
列,我必须在下拉列表显示时更新每个 ComboBox 的可能值。我还必须使 ComboBox
es 能够具有自定义类型的值。键入新值时,应将其添加到可能值列表中。问题是我得到了无限多个 DataError
事件触发器(错误消息框),我知道如何通过更改 DataGridViewDataErrorEventArgs
对象中的字段来处理它,但我知道这不是正确的方法处理它:
private void DataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
e.Cancel = false;
}
如果我以不正确的方式执行此操作,从下拉列表中选择一个值或输入一个新值后,CellValueChanged
会被触发,但关闭的 ComboBox
不会显示当前值但是一个已经存在的值(列表中的第一个)。
在下面的代码中,Form 子类是 Form2
,初始值存储在 str
字段中,并调用 UpdatePossibleValues
方法来更新所有可能的值ComboBox
es 在数据网格视图中唯一的列中,DataGridViewComboBoxColumn
:
public Form2()
{
InitializeComponent();
dataGridView1.EditingControlShowing += DataGridView1_EditingControlShowing;
UpdatePossibleValues();
}
internal List<string> str = new List<string>()
{
"val1",
"val2"
};
private void DataGridView1_EditingControlShowing(object sender,
DataGridViewEditingControlShowingEventArgs e)
{
if (dataGridView1.CurrentCell == null ||
dataGridView1.CurrentCell.OwningColumn == null ||
dataGridView1.CurrentCell.OwningColumn.Name != "column1")
{
return;
}
var combo = e.Control as DataGridViewComboBoxEditingControl;
if (combo == null)
{
return;
}
var cb = combo as ComboBox;
UpdatePossibleValues(cb);
cb.DropDownStyle = ComboBoxStyle.DropDown; // this makes the ComboBoxes editable
cb.Validating += Cb_Validating;
}
private void Cb_Validating(object sender, System.ComponentModel.CancelEventArgs e)
{
var cbo = sender as ComboBox;
string t = cbo.Text;
var cell = (DataGridViewComboBoxCell)dataGridView1.CurrentCell;
// add the value to the list if it is not there
if (!string.IsNullOrEmpty(t) &&
!cbo.Items.Contains(t))
{
str.Add(t);
UpdatePossibleValues(cbo);
cell.Value = t;
e.Cancel = false;
}
}
private void UpdatePossibleValues(ComboBox cb = null)
{
if (cb == null)
{
var col = dataGridView1.Columns[0] as DataGridViewComboBoxColumn;
col.Items.Clear();
foreach (string s in str)
{
col.Items.Add(s);
}
}
else
{
cb.Items.Clear();
foreach (string s in str)
{
cb.Items.Add(s);
}
}
}
截图:
动态添加项目到 DataGridViewComboBoxColumn
:
- 汉尔德
EditingControlShowing
并获得 DataGridViewComboBoxEditingControl
- 将编辑控件
DropDownStyle
设置为 DropDown
- 处理
Validating
编辑控件的事件并确保只附加一次事件处理程序。
- 检查项目中是否不存在编辑控件
Text
:
- 将其添加到列的数据源
- 然后通过将列设置为空并再次分配数据源来重置列的数据源。
备注:
如果您有多个组合框,请确保您对组合框使用不同的数据源,并在验证事件中更新相应的数据源。
如果您使用匿名方法处理事件,请确保您对捕获的变量有正确的假设。为了简单起见,您可以使用普通方法处理事件。
例子
以下示例显示了一个 DataGridView
有两个 DataGridViewComboBoxColumn
,对于第二个 DataGridViewComboBoxColumn
,您可以在 运行 时通过在组合框中键入来添加新值。
对于 运行 示例,创建一个 Form
并将 DataGridView
拖放到一个新表单上,然后只需将以下代码复制并粘贴到表单中:
private List<String> comboSource1;
private List<String> comboSource2;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
comboSource1 = new List<string> { "A", "B" };
comboSource2 = new List<string> { "1", "2" };
var dt = new DataTable();
dt.Columns.Add("C1");
dt.Columns.Add("C2");
dt.Rows.Add("A", "1");
dt.Rows.Add("B", "2");
var c1 = new DataGridViewComboBoxColumn();
c1.Name = "C1";
c1.DataPropertyName = "C1";
c1.DataSource = comboSource1;
var c2 = new DataGridViewComboBoxColumn();
c2.Name = "C2";
c2.DataPropertyName = "C2";
c2.DataSource = comboSource2;
dataGridView1.Columns.AddRange(c1, c2);
this.dataGridView1.DataSource = dt;
dataGridView1.EditingControlShowing += dataGridView1_EditingControlShowing;
dataGridView1.EditMode = DataGridViewEditMode.EditOnEnter;
}
private void dataGridView1_EditingControlShowing(object sender,
DataGridViewEditingControlShowingEventArgs e)
{
var dataGridView = sender as DataGridView;
if (dataGridView?.CurrentCell?.ColumnIndex != 1) return;
var comboBox = e.Control as DataGridViewComboBoxEditingControl;
if (comboBox == null) return;
comboBox.DropDownStyle = ComboBoxStyle.DropDown;
if (!true.Equals(comboBox.Tag))
{
comboBox.Tag = true;
comboBox.Validating += (obj, args) =>
{
var column = (DataGridViewComboBoxColumn)dataGridView.CurrentCell.OwningColumn;
var list = comboBox.DataSource as List<string>;
if (list == null) return;
var txt = comboBox.Text;
if (!list.Contains(txt))
{
list.Add(txt);
column.DataSource = null;
column.DataSource = list;
}
dataGridView.CurrentCell.Value = txt;
dataGridView.NotifyCurrentCellDirty(true);
};
}
}
我有一个 DataGridView
,它有一个 ComboBox
列,我必须在下拉列表显示时更新每个 ComboBox 的可能值。我还必须使 ComboBox
es 能够具有自定义类型的值。键入新值时,应将其添加到可能值列表中。问题是我得到了无限多个 DataError
事件触发器(错误消息框),我知道如何通过更改 DataGridViewDataErrorEventArgs
对象中的字段来处理它,但我知道这不是正确的方法处理它:
private void DataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
e.Cancel = false;
}
如果我以不正确的方式执行此操作,从下拉列表中选择一个值或输入一个新值后,CellValueChanged
会被触发,但关闭的 ComboBox
不会显示当前值但是一个已经存在的值(列表中的第一个)。
在下面的代码中,Form 子类是 Form2
,初始值存储在 str
字段中,并调用 UpdatePossibleValues
方法来更新所有可能的值ComboBox
es 在数据网格视图中唯一的列中,DataGridViewComboBoxColumn
:
public Form2()
{
InitializeComponent();
dataGridView1.EditingControlShowing += DataGridView1_EditingControlShowing;
UpdatePossibleValues();
}
internal List<string> str = new List<string>()
{
"val1",
"val2"
};
private void DataGridView1_EditingControlShowing(object sender,
DataGridViewEditingControlShowingEventArgs e)
{
if (dataGridView1.CurrentCell == null ||
dataGridView1.CurrentCell.OwningColumn == null ||
dataGridView1.CurrentCell.OwningColumn.Name != "column1")
{
return;
}
var combo = e.Control as DataGridViewComboBoxEditingControl;
if (combo == null)
{
return;
}
var cb = combo as ComboBox;
UpdatePossibleValues(cb);
cb.DropDownStyle = ComboBoxStyle.DropDown; // this makes the ComboBoxes editable
cb.Validating += Cb_Validating;
}
private void Cb_Validating(object sender, System.ComponentModel.CancelEventArgs e)
{
var cbo = sender as ComboBox;
string t = cbo.Text;
var cell = (DataGridViewComboBoxCell)dataGridView1.CurrentCell;
// add the value to the list if it is not there
if (!string.IsNullOrEmpty(t) &&
!cbo.Items.Contains(t))
{
str.Add(t);
UpdatePossibleValues(cbo);
cell.Value = t;
e.Cancel = false;
}
}
private void UpdatePossibleValues(ComboBox cb = null)
{
if (cb == null)
{
var col = dataGridView1.Columns[0] as DataGridViewComboBoxColumn;
col.Items.Clear();
foreach (string s in str)
{
col.Items.Add(s);
}
}
else
{
cb.Items.Clear();
foreach (string s in str)
{
cb.Items.Add(s);
}
}
}
截图:
动态添加项目到 DataGridViewComboBoxColumn
:
- 汉尔德
EditingControlShowing
并获得DataGridViewComboBoxEditingControl
- 将编辑控件
DropDownStyle
设置为DropDown
- 处理
Validating
编辑控件的事件并确保只附加一次事件处理程序。 - 检查项目中是否不存在编辑控件
Text
:- 将其添加到列的数据源
- 然后通过将列设置为空并再次分配数据源来重置列的数据源。
备注:
如果您有多个组合框,请确保您对组合框使用不同的数据源,并在验证事件中更新相应的数据源。
如果您使用匿名方法处理事件,请确保您对捕获的变量有正确的假设。为了简单起见,您可以使用普通方法处理事件。
例子
以下示例显示了一个 DataGridView
有两个 DataGridViewComboBoxColumn
,对于第二个 DataGridViewComboBoxColumn
,您可以在 运行 时通过在组合框中键入来添加新值。
对于 运行 示例,创建一个 Form
并将 DataGridView
拖放到一个新表单上,然后只需将以下代码复制并粘贴到表单中:
private List<String> comboSource1;
private List<String> comboSource2;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
comboSource1 = new List<string> { "A", "B" };
comboSource2 = new List<string> { "1", "2" };
var dt = new DataTable();
dt.Columns.Add("C1");
dt.Columns.Add("C2");
dt.Rows.Add("A", "1");
dt.Rows.Add("B", "2");
var c1 = new DataGridViewComboBoxColumn();
c1.Name = "C1";
c1.DataPropertyName = "C1";
c1.DataSource = comboSource1;
var c2 = new DataGridViewComboBoxColumn();
c2.Name = "C2";
c2.DataPropertyName = "C2";
c2.DataSource = comboSource2;
dataGridView1.Columns.AddRange(c1, c2);
this.dataGridView1.DataSource = dt;
dataGridView1.EditingControlShowing += dataGridView1_EditingControlShowing;
dataGridView1.EditMode = DataGridViewEditMode.EditOnEnter;
}
private void dataGridView1_EditingControlShowing(object sender,
DataGridViewEditingControlShowingEventArgs e)
{
var dataGridView = sender as DataGridView;
if (dataGridView?.CurrentCell?.ColumnIndex != 1) return;
var comboBox = e.Control as DataGridViewComboBoxEditingControl;
if (comboBox == null) return;
comboBox.DropDownStyle = ComboBoxStyle.DropDown;
if (!true.Equals(comboBox.Tag))
{
comboBox.Tag = true;
comboBox.Validating += (obj, args) =>
{
var column = (DataGridViewComboBoxColumn)dataGridView.CurrentCell.OwningColumn;
var list = comboBox.DataSource as List<string>;
if (list == null) return;
var txt = comboBox.Text;
if (!list.Contains(txt))
{
list.Add(txt);
column.DataSource = null;
column.DataSource = list;
}
dataGridView.CurrentCell.Value = txt;
dataGridView.NotifyCurrentCellDirty(true);
};
}
}