将ComboBox数据集复制到DataGridViewComboBoxColumn

时间:2017-02-13 17:01:28

标签: c# datagridview combobox

(使用C#Visual Studio 2015,Windows窗体)

我有一个我希望在DataGridView(DGV)中显示的字符串列表。

DGV中的每一行都有:

  • column [0]:列表中的字符串值( ColumnType:DataGridViewTextBoxColumn
  • 列[1]:一个空白单元格(用户将在此处输入数据)( ColumnType:DataGridViewTextBoxColumn
  • 专栏[2]:ComboBox( ColumnType:DataGridViewComboBoxColumn

每条记录中的每个ComboBox都有相同的项目(相同的DataSet),我将这些从SQL查询中检索到我的Access数据库(accdb)。

我的主要问题是我需要识别每个ComboBox的ValueMemberDisplayMember,而我无法弄清楚如何做到这一点。我当前的代码只是尝试将DataTable results复制到ComboBox中,但我收到了错误:
System.ArgumentException.DataGridViewComboBoxCell value is not valid.

enter image description here

它会重复DataGridView中每个ComboBox的每个值。我无法弄清楚我做错了什么。

非常感谢任何帮助。这是代码:

     DataTable results = new DataTable();

     //Identify the Connection String
     connection.ConnectionString = dbQuery.connStr;

     //SQL Statement to retrieve ComboBox Items
     string sql = @"SELECT ID, DESCRIP FROM tbl_setpoints_categories ORDER BY DESCRIP ASC";

     //Create a new ComboBox (this is for testing purposes)
     ComboBox cb = new ComboBox();

        try
        {
            connection.Open();
            OleDbCommand command = new OleDbCommand();
            command.Connection = connection;
            command.CommandText = sql;
            OleDbDataReader reader = command.ExecuteReader();

            results.Columns.Add("ID", typeof(int));
            results.Columns.Add("DESCRIP", typeof(string));
            results.Load(reader);

            //For testing purposes...
            cb.ValueMember = "ID";
            cb.DisplayMember = "DESCRIP";
            cb.DataSource = results;

            if (!reader.IsClosed)
            {
                reader.Close();
            }
        }
        finally
        {
            connection.Close();
        }


        //Loop through the list and add each into an array of objects
        //This array will be added as a DataGridView row
        foreach (string spName in spList)
        {

            //My Latest Edit, but still produces same error
            DataGridViewComboBoxCell cbCell = new DataGridViewComboBoxCell();
            cbCell.ValueMember = "ID";
            cbCell.DisplayMember = "DESCRIP";
            cbCell.DataSource = results;
            //End Latest Edit

            object[] row = new object[3];
            row[0] = spName.ToString();
            row[1] = "";
            row[2] = cbCell;  //From Latest Edit (was: results)
            dataGridView1.Rows.Add(row);
        }

编辑:我刚检查一下我的查询是否通过添加此行来拉取记录:
MessageBox.Show(results.Rows.Count.ToString());
我收到了正确的记录数

1 个答案:

答案 0 :(得分:0)

希望这可能会让事情变得清晰起来。很遗憾,DataGridViewComboBoxColumn不是ComboBox控件列。因此,以下行不会用作DataGridView列。

ComboBox cb = new ComboBox();
cb.ValueMember = "ID";
cb.DisplayMember = "DESCRIP";
cb.DataSource = results;

DataGridViewDataGridViewComboBoxColumn,实际上比常规ComboBox更具挑战性。所以为了帮助想象这一点,我制作了一张图画来展示我所描述的内容。

enter image description here

上面你可以看到下面代码的输出。我使用按钮单击放置断点来显示两个DataTablesDataGridViewComboBoxColumn DataSource是具有不同“设定点类型”的DataTable,并在右侧显示“Id”和“设定点类型”0-14。这些是DataGridViewComboBoxColumn用作DataSource.

的项目

方便的部分是,为此列设置DataSource后,您不必使用每个新/现有单元更新此列。该列将自动构建ComboBoxCells。当您使用所有数据为主DataTable创建DataGridView时,您会假设组合框列所在的单元格需要具有所有值。但是这些值只是一个匹配组合框中某个项目的字符串(希望如此)。因此,DataGridView DataTable(不是DataGridView列)需要将此列设为字符串(而不是组合框),因为它只能包含来自不同“设置点类型”的一个值类型。方便的方面是即使它是一个字符串而不是一个组合框,如果它与组合框中的现有项匹配,那么它将显示该项。

以下是上图所用的代码。

首先使用两个文本列设置DataGridView列,然后将最后一列设置为DataGridViewComboBoxColumnGetComboColumn方法返回DatGridViewComboBoxColumn,其中包含组合框的不同项。相关属性为DataPropertyNameDisplayMemeberValueMember,这些属性标识了DataSource中要使用的列。下面是一个向DataTable添加文本列的方法。

最后,我们为DataTable获取DataGridView,其中包含一些测试数据。希望这会有所帮助。

DataTable allData;
DataTable comboTable;

public Form1() {
  InitializeComponent();
}

//-------------------------------------------------------------------------
private void Form1_Load(object sender, EventArgs e) {
  SetDGVColumns();
  allData = GetAllData();
  dataGridView1.DataSource = allData;
}

private DataTable GetAllData() {
  DataTable data = new DataTable();
  data.Columns.Add("Set Point Name", typeof(string));
  data.Columns.Add("Description", typeof(string));
  data.Columns.Add("Set Point Type", typeof(string));  // <-- NOTE: this is a string- not a combo box

  data.Rows.Add("nai_m2_no2", "Description 0", "Set Point Type 4");
  data.Rows.Add("nao_enth_no3", "Description 1", "Set Point Type 13");
  data.Rows.Add("nai_m2_no4", "Description 2", "Set Point Type 4");
  data.Rows.Add("nai_m2_no5", "Description 3", "Set Point Type 11");
  data.Rows.Add("nai_m2_no6", "Description 4", "Set Point Type 3");
  data.Rows.Add("nai_m2_no7", "Description 5", "Set Point Type 2");
  return data;
}

//-------------------------------------------------------------------------
private void SetDGVColumns() {
  AddTextCol("Set Point Name");
  AddTextCol("Description");
  dataGridView1.Columns.Add(GetComboColumn()); // <-- THIS DataGridView Column needs to be a combo box column
}

//-------------------------------------------------------------------------
private DataGridViewComboBoxColumn GetComboColumn() {
  comboTable = new DataTable();
  comboTable.Columns.Add("ID", typeof(int));
  comboTable.Columns.Add("Set Point Type", typeof(string));
  for (int i = 0; i < 15; i++) {
    comboTable.Rows.Add(i, "Set Point Type " + i);
  }
  // we now have a data table to use as a data source for the DataGridViewComboBoxColumn
  // make a DataGridViewComboBoxColumn and set it properties
  DataGridViewComboBoxColumn typeCol = new DataGridViewComboBoxColumn();
  typeCol.Width = 150;
  typeCol.DataPropertyName = "Set Point Type";  //<-- needs to match the DataTable column name you want to display - in this case 'Set Point Type'
  typeCol.HeaderText = "Set Point Type";
  typeCol.ValueMember = "Set Point Type";
  typeCol.DisplayMember = "Set Point Type";
  typeCol.Name = "Set Point Type";
  typeCol.DataSource = comboTable;
  return typeCol;
}

//-------------------------------------------------------------------------
private void AddTextCol(string colInfo) {
  DataGridViewTextBoxColumn TextCol = new DataGridViewTextBoxColumn();
  TextCol.DataPropertyName = colInfo;
  TextCol.HeaderText = colInfo;
  TextCol.Name = colInfo;
  dataGridView1.Columns.Add(TextCol);
}