创建DataGridView列以映射数据源中的值

时间:2018-08-17 11:08:31

标签: c# .net winforms datagridview datatable

我有一个DataTable,其中包含一些数据,例如像这样:

| id  |  name | type_id |
+-----+-------+---------+
| 0   |   joe |     156 |
| 1   | alice |      23 |

DataTable中的数据来自SQL-ish数据库。我也有DataGridView,应显示以下内容:

|  name | type_name |
+-------+-----------+
|   joe |     admin |
| alice |      user |

我有一种方法可以将type_id查找到type_name。我添加了DataGridViewComboBoxColumn,当它更改时,我更新了基础表中的type_id

    private void cellValueChanged(object sender, DataGridViewCellEventArgs e)
    {
        // find the cell
        DataGridViewCell cell = dataGridView[e.ColumnIndex, e.RowIndex];
        string columnName = dataGridView.Columns[e.ColumnIndex]?.Name ?? "";

        // check if combo cell is in this column for sure
        if(cell is DataGridViewComboBoxCell comboCell)
        {   
            // Only user type is subject to this event
            if(columnName == "type_name")
            {
                // BIG NOTE: THE LOOKUP HERE COULD (and is) BE MORE COMPLEX!
                // This is just an example for stack overflow

                object cellVal = comboCell.Value;
                // Only numeric values
                // Combobox displays string names, but contains numeric values
                if(cellVal!=null && IsNumber(cellVal))
                {
                    // change the underlying datatable, not the grid view
                    dataTable.Rows[e.RowIndex]["type_id"] = cellVal;
                }
            }
        }
    }

但是我也想拥有一个相反的版本。加载DataGridView时,组合框列中的值为空。我该如何编写一个片段代码,将值从DataTable列映射到 DataGridView列

注意:在我的实际情况中,映射比数字->字符串还要复杂。涉及多个值。因此,必须真正创建新列!

1 个答案:

答案 0 :(得分:1)

不清楚“ type_id”是什么值映射到“ type_name”。换句话说,当前,如果“ type_id”是int 156,则“ type_name”是string“ admin”。 ”“ type_id”中是否还有其他数字也会产生“ admin”?

如果是一对一关系,则具有此映射的DataTable将适用于组合框,您将能够将组合框列直接映射到网格DataTable.例如,如果存在一对一关系,则组合框的DataTable将具有两个属性,“ type_id”的int和“ type_name”的string。 ”

使用正确的映射填充表格,然后设置组合框的DataSource指向该表格。将组合框DataPropertyName设置为“ type_id”会将此列映射到网格DataSource.中的相同列名。使用这种方法,用户将在以下位置看到“ admin”“ user”等...组合框,如果它们更改了其值,则网格中的DataTable将自动更新int“ type_id”值。无需手动设置值。如果正确设置了组合框,则可以使用此功能。

下面是一个示例。

如果存在一对多关系,那么我可以发布另一种解决方案。下面是上面描述的示例。

该表单有两个DataGridView。两个网格都使用与DataTable相同的DataSource.顶部网格仅显示我们想要的两列……“名称”和“ type_id”。“ type_id”列是组合框列,将显示int“ type_id”的正确“ type_name”。

enter image description here

连接顶部网格CurrentCellDirtyStateChanged事件以更新底部网格上的DataSource,以显示int“ type_id”值在用户更改组合框单元格时自动更改值。

我希望这是有道理的。

DataTable dataTable;
DataTable comboData;

public Form2() {
  InitializeComponent();
}

private void Form2_Load(object sender, EventArgs e) {
  dataTable = GetTable();
  FillTable(dataTable);
  FillComboTable();
  SetGridColumns(dataGridView1);
  dataGridView1.AutoGenerateColumns = false;
  dataGridView1.DataSource = dataTable;
  dataGridView2.DataSource = dataTable;
}

private DataTable GetTable() {
  DataTable dt = new DataTable();
  dt.Columns.Add("id", typeof(int));
  dt.Columns.Add("name", typeof(string));
  dt.Columns.Add("type_id", typeof(int));
  return dt;
}

private void FillTable(DataTable dt) {
  dt.Rows.Add(0, "joe", 156);
  dt.Rows.Add(1, "alice", 23);
  dt.Rows.Add(2, "mark", 0);
  dt.Rows.Add(3, "sally", 44);
  dt.Rows.Add(4, "gabe", 133);
}

private DataTable GetComboTable() {
  DataTable dt = new DataTable();
  dt.Columns.Add("value", typeof(int));
  dt.Columns.Add("name", typeof(string));
  return dt;
}

private void FillComboTable() {
  comboData = GetComboTable();
  comboData.Rows.Add(156, "admin");
  comboData.Rows.Add(23, "user");
  comboData.Rows.Add(44, "database");
  comboData.Rows.Add(133, "system");
  comboData.Rows.Add(0, " ");
}

private void SetGridColumns(DataGridView dgv) {
  DataGridViewTextBoxColumn col1 = new DataGridViewTextBoxColumn();
  col1.HeaderText = "name";
  col1.Name = "name";
  col1.DataPropertyName = "name";
  dgv.Columns.Add(col1);
  DataGridViewComboBoxColumn combo = new DataGridViewComboBoxColumn {
    HeaderText = "type_id",
    Name = "type_id",
    DataPropertyName = "type_id",
    DataSource = comboData,
    DisplayMember = "name",
    ValueMember = "value"
  };
  dgv.Columns.Add(combo);
}

private void dataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e) {
  MessageBox.Show("Data Error: " + e.Exception.Message);
}

private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e) {
  if (dataGridView1.IsCurrentCellDirty) {
    dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
    dataGridView2.DataSource = null;
    dataGridView2.DataSource = dataTable;
  }
}