无法将 DataGridViewComboBoxColumn 中的值设置为绑定的 DataGridView
Cannot set values from a DataGridViewComboBoxColumn to a bound DataGridView
我有一个最初加载数据并显示它的 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();
}
这是我尝试添加 ComboBox 列的 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;
}
当我点击下拉列表时,没有任何反应:
用作DataGridView 的DataSource 的DataTable 有一个自增列。您不能将此列用作 ProductId
,它可以由用户通过 ComboBox select 或更改。它会弄得一团糟(除非它只是用来构建 MCVE)。
您可以将此列用作主键 - 还可以设置 Unique = true
.
改为添加代表 ProductId
键的 int
列,它链接 ProductName
列,该列是 DataTable 的一部分,设置为 ComboBox 列的数据源。
由于ComboBox的ValueMember
属性设置为ProductId
值并且ComboBox Column绑定到DataGridView DataTable的ProductId
Column,改变ComboBox的SelectdItem将更改用作 DataGridView 数据源的 DataTable 的 ProductId
列的值。
添加到BindProductsGrid()
方法:
dtGrid.PrimaryKey = new[] { pkColumn };
dtGrid.AcceptChanges();
(必填项)
dgvProducts.Columns["ProductId"].ReadOnly = true;
和
dgvProducts.AllowUserToAddRows = false;
(因为这似乎是意图:让用户仅使用 ComboBox select 或) 指定产品
在设置DataGridView的DataSource后添加DataGridViewComboBoxColumn
。这是因为此列绑定到 ProductId
列,作为 DataGridView 的 DataTable 的相应列。
它允许在代码中向 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;
}
现在,进行一些调整以使产品 selection 更 响应:
(➨ 注意 DataGridView 被命名为 dgvProducts
)
EditingControlShowing
处理程序订阅 ComboBox 单元格 SelectedIndexChanged
事件
ComboBox SelectedIndexChanged
处理程序异步调用 Validate()
,以立即显示 ComboBox selection(无需 select 另一个 Cell 即可查看它应用了)
BeginInvoke(new Action(() => Validate()));
DataGridView CellContentClick
处理程序将 ComboBox 的样式更改为 DataGridViewComboBoxDisplayStyle.ComboBox
CellLeave
处理程序将 ComboBox 样式恢复为 DataGridViewComboBoxDisplayStyle.Nothing
,因此它看起来像一个 TextBox。
▶ 如果您只想 hide/show 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;
}
}
}
这是使用此处显示的代码的工作原理:
我有一个最初加载数据并显示它的 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();
}
这是我尝试添加 ComboBox 列的 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;
}
当我点击下拉列表时,没有任何反应:
用作DataGridView 的DataSource 的DataTable 有一个自增列。您不能将此列用作 ProductId
,它可以由用户通过 ComboBox select 或更改。它会弄得一团糟(除非它只是用来构建 MCVE)。
您可以将此列用作主键 - 还可以设置 Unique = true
.
改为添加代表 ProductId
键的 int
列,它链接 ProductName
列,该列是 DataTable 的一部分,设置为 ComboBox 列的数据源。
由于ComboBox的ValueMember
属性设置为ProductId
值并且ComboBox Column绑定到DataGridView DataTable的ProductId
Column,改变ComboBox的SelectdItem将更改用作 DataGridView 数据源的 DataTable 的 ProductId
列的值。
添加到BindProductsGrid()
方法:
dtGrid.PrimaryKey = new[] { pkColumn };
dtGrid.AcceptChanges();
(必填项)dgvProducts.Columns["ProductId"].ReadOnly = true;
和dgvProducts.AllowUserToAddRows = false;
(因为这似乎是意图:让用户仅使用 ComboBox select 或) 指定产品
在设置DataGridView的DataSource后添加DataGridViewComboBoxColumn
。这是因为此列绑定到 ProductId
列,作为 DataGridView 的 DataTable 的相应列。
它允许在代码中向 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;
}
现在,进行一些调整以使产品 selection 更 响应:
(➨ 注意 DataGridView 被命名为 dgvProducts
)
EditingControlShowing
处理程序订阅 ComboBox 单元格SelectedIndexChanged
事件ComboBox
SelectedIndexChanged
处理程序异步调用Validate()
,以立即显示 ComboBox selection(无需 select 另一个 Cell 即可查看它应用了)BeginInvoke(new Action(() => Validate()));
DataGridView
CellContentClick
处理程序将 ComboBox 的样式更改为DataGridViewComboBoxDisplayStyle.ComboBox
CellLeave
处理程序将 ComboBox 样式恢复为DataGridViewComboBoxDisplayStyle.Nothing
,因此它看起来像一个 TextBox。
▶ 如果您只想 hide/show 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;
}
}
}
这是使用此处显示的代码的工作原理: