首页 > 解决方案 > 创建从数据源映射值的 DataGridView 列

问题描述

我有一个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 列

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

标签: c#.netwinformsdatagridviewdatatable

解决方案


目前尚不清楚“type_id”映射到“type_name”的值。也就是说,目前如果“type_id”是int156,那么“type_name”就是string“admin”。“type_id”中是否还有其他数字也会产生“admin”?</p>

如果它是一对一关系,那么DataTable具有此映射的 a 将适用于组合框,并且您可以将组合框列直接映射到网格DataTable.示例,如果存在一对一关系,则组合框的DataTablefor 将有两个属性,一个int用于“type_id”,一个string用于“type_name”。</p>

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

下面是一个例子。

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

表格有两个DataGridViews。两个网格都使用相同DataTableDataSource.顶部网格,只显示我们想要的两列……“name”和“type_id”。“type_id”列是组合框列,将为“type_id”显示正确的“type_name” int。</p>

在此处输入图像描述

顶部网格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;
  }
}

推荐阅读