无法将 DataGridViewComboBoxColumn 中的值设置为绑定的 DataGridView
Posted
技术标签:
【中文标题】无法将 DataGridViewComboBoxColumn 中的值设置为绑定的 DataGridView【英文标题】:Cannot set values from a DataGridViewComboBoxColumn to a bound DataGridView 【发布时间】:2021-09-22 17:41:57 【问题描述】:我有一个 DataGridView,它最初会加载数据并显示它。 当用户单击编辑按钮时,我通过隐藏其中一个列来添加 DataGridViewComboBoxColumn。
private DataTable BindCombo()
DataTable dt = new DataTable();
dt.Columns.Add("ProductId", typeof(int));
dt.Columns.Add("ProductName", typeof(string));
dt.Rows.Add(1, "Product1");
dt.Rows.Add(2, "Product2");
return dt;
private void BindGrid()
DataTable dtGrid = new DataTable();
DataColumn column = new DataColumn("ProductId")
DataType = System.Type.GetType("System.Int32"),
AutoIncrement = true,
AutoIncrementSeed = 1,
AutoIncrementStep = 1
;
dtGrid.Columns.Add(column);
dtGrid.Columns.Add("ProductName", typeof(string));
dtGrid.Rows.Add(null, "Product1");
dtGrid.Rows.Add(null, "Product2");
dataGridView1.DataSource = dtGrid;
private void Form1_Load(object sender, EventArgs e)
BindGrid();
这是我尝试添加组合框列的Button.Click
事件:
private void btnEdit_Click(object sender, EventArgs e)
dataGridView1.AllowUserToAddRows = true;
dataGridView1.ReadOnly = false;
dataGridView1.Columns[1].Visible = false;
DataGridViewComboBoxColumn col1 = new DataGridViewComboBoxColumn
DisplayStyle = DataGridViewComboBoxDisplayStyle.DropDownButton,
HeaderText = "Product Name",
DataSource = BindCombo(),
ValueMember = "ProductId",
DisplayMember = "ProductName",
DataPropertyName = "ProductId"
;
dataGridView1.Columns.Add(col1);
dataGridView1.AllowUserToAddRows = false;
当我点击下拉菜单时,什么也没有发生:
【问题讨论】:
【参考方案1】:用作 DataGridView 的 DataSource 的 DataTable 有一个自增列。您不能将此列用作ProductId
,用户可以通过组合框选择器更改它。它会弄得一团糟(除非它只是用于构建 MCVE)。
您可以将此列用作主键 - 也可以设置 Unique = true
。
改为添加一个代表ProductId
键的int
列,它链接作为组合框列的数据源的DataTable 的一部分的ProductName
列。
由于 ComboBox 的 ValueMember
属性设置为 ProductId
值,并且 ComboBox Column 绑定到 DataGridView 数据表的 ProductId
Column,因此更改 ComboBox 的 SelectdItem 将更改 ProductId
Column 的值用作 DataGridView 的数据源的 DataTable。
添加到 BindProductsGrid()
方法中:
dtGrid.PrimaryKey = new[] pkColumn ;
dtGrid.AcceptChanges();
(必填)
dgvProducts.Columns["ProductId"].ReadOnly = true;
和
dgvProducts.AllowUserToAddRows = false;
(因为这似乎是意图:让用户仅使用 ComboBox 选择器指定产品)
DataGridViewComboBoxColumn
是在DataGridView的DataSource设置后添加的。这是因为这个Column绑定到ProductId
Column,作为DataGridView的DataTable的对应Column。
它允许在代码中向 DataGridView 添加绑定到数据源同一列的两个列,而不会混淆控件。
private void BindProductsGrid()
var dtGrid = new DataTable();
var pkColumn = new DataColumn("ID")
DataType = typeof(int),
AutoIncrement = true,
AutoIncrementSeed = 1,
AutoIncrementStep = 1,
Unique = true
;
var productColumn = new DataColumn("ProductId")
DataType = typeof(int),
Caption = "Product Id"
;
dtGrid.Columns.Add(pkColumn);
dtGrid.Columns.Add(productColumn);
dtGrid.Rows.Add(null, 1);
dtGrid.Rows.Add(null, 2);
dtGrid.Rows.Add(null, 3);
dtGrid.Rows.Add(null, 4);
dtGrid.PrimaryKey = new[] pkColumn ;
dtGrid.AcceptChanges();
dgvProducts.DataSource = dtGrid;
dgvProducts.Columns["ID"].Visible = false;
dgvProducts.Columns["ProductId"].ReadOnly = true;
var productName = new DataGridViewComboBoxColumn
DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing,
Name = "ProductName",
HeaderText = "Product Name",
ValueMember = "ProductId",
DisplayMember = "ProductName",
DataSource = BindCombo(),
DataPropertyName = "ProductId",
DisplayIndex = 2
;
dgvProducts.Columns.Add(productName);
dgvProducts.AllowUserToAddRows = false;
作为ComboBox的数据源的DataTable有两个相同的Column,只是在前面的代码中增加了AcceptChanges()
(可选):
private DataTable BindCombo()
var dt = new DataTable();
dt.Columns.Add("ProductId", typeof(int));
dt.Columns.Add("ProductName", typeof(string));
dt.Rows.Add(1, "Product1");
dt.Rows.Add(2, "Product2");
dt.Rows.Add(3, "Product3");
dt.Rows.Add(4, "Product4");
dt.AcceptChanges();
return dt;
现在,进行一些调整以使产品选择更具响应性:
(➨ 请注意,DataGridView 被命名为 dgvProducts
)
EditingControlShowing
处理程序订阅 ComboBox Cell SelectedIndexChanged
事件
ComboBox SelectedIndexChanged
处理程序异步调用 Validate()
,以立即显示 ComboBox 选择(无需选择另一个 Cell 即可看到它已应用)
BeginInvoke(new Action(() => Validate()));
DataGridView CellContentClick
处理程序将 ComboBox 的样式更改为 DataGridViewComboBoxDisplayStyle.ComboBox
CellLeave
处理程序将 ComboBox 样式恢复为 DataGridViewComboBoxDisplayStyle.Nothing
,因此它看起来像一个 TextBox。
▶ 如果您只想隐藏/显示 ProductName
列,则可以不使用 CellContentClick
和 CellLeave
处理程序并保留初始 ComboBox 样式。
private void dgvComboBox_SelectedIndexChanged(object sender, EventArgs e)
(sender as ComboBox).SelectedIndexChanged -= dgvComboBox_SelectedIndexChanged;
BeginInvoke(new Action(() => Validate()));
private void dgvProducts_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
if (e.Control is ComboBox cbo)
cbo.SelectedIndexChanged += dgvComboBox_SelectedIndexChanged;
private void dgvProducts_CellContentClick(object sender, DataGridViewCellEventArgs e)
if (e.RowIndex > 0 && e.ColumnIndex == 2)
if (dgvProducts[2, e.RowIndex] is DataGridViewComboBoxCell cbox)
cbox.DisplayStyle = DataGridViewComboBoxDisplayStyle.ComboBox;
private void dgvProducts_CellLeave(object sender, DataGridViewCellEventArgs e)
if (e.RowIndex < 0) return;
if (dgvProducts.Columns[e.ColumnIndex].Name == "ProductName")
if (dgvProducts["ProductName", e.RowIndex] is DataGridViewComboBoxCell cbox)
cbox.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing;
这是使用此处显示的代码的工作原理:
【讨论】:
以上是关于无法将 DataGridViewComboBoxColumn 中的值设置为绑定的 DataGridView的主要内容,如果未能解决你的问题,请参考以下文章
无法将 createdAt 和 updatedAt 保存为日期时间值,也无法将后端保存为前端
C# 无法将类型为“System.Byte[]”的对象强制转换为类型“System.Data.DataTable
无法将类型为“System.Collections.Generic.List`1[EPMS.Domain.SingleItem]”的对象强制转换为类型“EPMS