简体   繁体   English

无法将 DataGridViewComboBoxColumn 中的值设置为绑定的 DataGridView

[英]Cannot set values from a DataGridViewComboBoxColumn to a bound DataGridView

I am having a DataGridView that initially loads data and shows it.我有一个 DataGridView,它最初加载数据并显示它。
When an user clicks an Edit Button, I am adding a DataGridViewComboBoxColumn by hiding one of the Columns.当用户单击编辑按钮时,我通过隐藏其中一个列来添加 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();
 }

Here is the Button.Click event where I am trying to add a ComboBox Column:这是我尝试添加 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;
    }

When I click on drop down, nothing happens:当我点击下拉菜单时,没有任何反应:

在此处输入图片说明

The DataTable used as the DataSource of your DataGridView has an auto-increment Column.用作 DataGridView 的数据源的 DataTable 有一个自动增量列。 You cannot use this Column as the ProductId , which can be changed by an User via the ComboBox selector.您不能将此 Column 用作ProductId ,用户可以通过 ComboBox 选择器更改它。 It will make a mess (unless this was used just just to build a MCVE).它会弄得一团糟(除非它只是用来构建 MCVE)。
You can use this Column as the Primary Key - setting also Unique = true .您可以将此列用作主键 - 也可以设置Unique = true

Add instead a int Column that represents the ProductId Key, which links the ProductName Column that is part of the DataTable set as the DataSource of the ComboBox Column.添加一个表示ProductId键的int列,该列链接作为 DataTable 一部分的ProductName列,该列设置为 ComboBox 列的数据源。
Since the ValueMember property of the ComboBox is set to the ProductId value and the ComboBox Column is bound to the ProductId Column of the DataGridView DataTable, changing the SelectdItem of the ComboBox will change the value of the ProductId Column of the DataTable used as data source of your DataGridView.由于 ComboBox 的ValueMember属性设置为ProductId值,并且 ComboBox Column 绑定到 DataGridView DataTable 的ProductId列,因此更改 ComboBox 的 SelectdItem 将更改用作数据源的 DataTable 的ProductId列的值你的数据网格视图。

Added to the BindProductsGrid() method:添加到BindProductsGrid()方法:

  • dtGrid.PrimaryKey = new[] { pkColumn };
  • dtGrid.AcceptChanges(); (mandatory) (强制的)
  • dgvProducts.Columns["ProductId"].ReadOnly = true; and
  • dgvProducts.AllowUserToAddRows = false; (since this seems to be the intention: let the User specify the Product only using the ComboBox selector) (因为这似乎是意图:让用户仅使用 ComboBox 选择器指定产品)

The DataGridViewComboBoxColumn is added after the DataSource of the DataGridView is set. DataGridViewComboBoxColumn是在DataGridView 的DataSource 设置之后添加的。 This because this Column is bound to the ProductId Column, as the corresponding Column of the DataGridView's DataTable.这是因为此 Column 绑定到ProductId列,作为 DataGridView 的 DataTable 的对应列。
It allows to add to the DataGridView two Columns bound to the same Column of the data source in code, without confusing the Control.它允许在代码中向 DataGridView 添加绑定到数据源的同一 Column 的两个 Column,而不会混淆Control。

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;
}

The DataTable used as data source of the ComboBox has the same two Columns, just AcceptChanges() (optional) is added to the previous code:作为 ComboBox 数据源的 DataTable 具有相同的两列,只是在前面的代码中添加了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;
}

Now, some adjustments to make the Product selection more responsive :现在,进行一些调整以使产品选择更具响应性
(➨ note that the DataGridView is named dgvProducts ) (➨ 注意 DataGridView 被命名为dgvProducts

  • The EditingControlShowing handler subscribes to the ComboBox Cell SelectedIndexChanged event EditingControlShowing处理程序订阅 ComboBox Cell SelectedIndexChanged事件

  • The ComboBox SelectedIndexChanged handler invokes asynchronously Validate() , to show the ComboBox selection immediately (no need to select another Cell to see it applied) ComboBox SelectedIndexChanged处理程序异步调用Validate() ,以立即显示 ComboBox 选择(无需选择另一个单元格来查看它的应用)

     BeginInvoke(new Action(() => Validate()));
  • The DataGridView CellContentClick handler changes the style of the ComboBox to DataGridViewComboBoxDisplayStyle.ComboBox DataGridView CellContentClick处理程序将 ComboBox 的样式更改为DataGridViewComboBoxDisplayStyle.ComboBox

  • CellLeave handler restores the ComboBox style to DataGridViewComboBoxDisplayStyle.Nothing , so it looks like a TextBox. CellLeave处理程序将 ComboBox 样式恢复为DataGridViewComboBoxDisplayStyle.Nothing ,因此它看起来像一个 TextBox。

▶ If you instead want to just hide/show the ProductName column, you can do without the CellContentClick and CellLeave handlers and keep the initial ComboBox style. ▶ 如果您只想隐藏/显示ProductName列,您可以不使用CellContentClickCellLeave处理程序并保留初始 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;
        }
    }
}

This how it works using the code shown here:这是使用此处显示的代码的工作方式:

DataGridView ComboBoxColumn 选择器

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 将DataGridViewColumn更改为绑定DataGridView中的DataGridViewComboBoxColumn - Change DataGridViewColumn to DataGridViewComboBoxColumn in bound DataGridView 如何将DataGridView列设置为DataGridViewComboBoxColumn? - How to set a DataGridView column to a DataGridViewComboBoxColumn? 将DataGridViewComboBoxColumn添加到DataGridView,每行中具有不同的值 - Add DataGridViewComboBoxColumn to DataGridView, with different values in each row 绑定 DataGridView:当我在 DataGridViewComboBoxColumn 外部单击时,它会更改为不同的值 - Bound DataGridView: the DataGridViewComboBoxColumn changes to a different value when I click outside it DataGridViewComboBoxColumn中的非String值导致DataGridView中的DataErrors - Non-String values in DataGridViewComboBoxColumn causing DataErrors in DataGridView 绑定网格的DataGridViewComboboxColumn - DataGridViewComboboxColumn for Bound Grid 绑定到DataTable的DataGridViewComboBoxColumn上的DataError - DataError on DataGridViewComboBoxColumn bound to a DataTable 如何将 DataGridViewComboBoxColumn 绑定到 object? - How to bound a DataGridViewComboBoxColumn to a object? datagridviewcomboboxcolumn未与datagridview返回 - datagridviewcomboboxcolumn not returned with datagridview DataGridViewComboBoxColumn不填充数据源中的值 - DataGridViewComboBoxColumn not populating values from the data source
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM