C# - DataGridView 主从与 DataGridViewComboBoxColumn

C# - DataGridView master-detail with DataGridViewComboBoxColumn

我对一些本应很简单的东西感到迷茫。

我有两个数据集,都包含两个数据表。每个 DataTable 都是我从两个数据库的架构中读取的表名和列名的列表。

我在主从模式下将表的列表 DataTable 绑定到 DataGridView,将列的列表 DataTable 绑定到第二个 DataGridView。第一个数据集一切正常。

然后我向每个 DataGridView 添加两个 DataGridViewComboBoxColumn,并将这些列的 ComboBox 绑定到第二个 DataSet。

当您 select 主 DataGridView 中的一行时,详细 DataGridView 会填充与 selected 行相关的列。 但是,详细 DataGridView 中的 DataGridViewComboBoxColumn 仅在主 DataGridView 中的 DataGridViewComboBoxColumn 被 selected 时才会更新。

知道如何 link 主网格中的行 selection 到 ComboBox 吗?

希望问题够清楚, 感谢您的帮助!

using System;
using System.Data;
using System.Windows.Forms;

namespace MasterDetailTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private DataGridView dataGridView1 = new DataGridView();
        private DataSet dataSet1 = new DataSet();
        private BindingSource bindingSourceTables1 = new BindingSource();
        private BindingSource bindingSourceColumns1 = new BindingSource();

        private DataGridView dataGridView2 = new DataGridView();
        private DataSet dataSet2 = new DataSet();
        private BindingSource bindingSourceTables2 = new BindingSource();
        private BindingSource bindingSourceColumns2 = new BindingSource();


        private void Form1_Load(object sender, EventArgs e)
        {
            SetGrids(dataGridView1, dataGridView2);

            dataGridView1.DataSource = bindingSourceTables1;
            dataGridView2.DataSource = bindingSourceColumns1;

            // DataSet1
            DataTable tables1 = new DataTable("tables1");
            tables1.Columns.Add(new DataColumn("TABLE_NAME", typeof(string)));
            tables1.Columns.Add(new DataColumn("TABLE_NAME2", typeof(string))); //Map DataSet2's table name to DataSet1's table name

            DataTable columns1 = new DataTable("columns1");
            columns1.Columns.Add(new DataColumn("TABLE_NAME", typeof(string)));
            columns1.Columns.Add(new DataColumn("COLUMN_NAME", typeof(string)));
            columns1.Columns.Add(new DataColumn("COLUMN_NAME2", typeof(string)));   //Map DataSet2's column name to DataSet1's column name

            dataSet1.Tables.Add(tables1);
            dataSet1.Tables.Add(columns1);

            tables1.PrimaryKey = new DataColumn[] { tables1.Columns["TABLE_NAME"] };
            columns1.PrimaryKey = new DataColumn[] { columns1.Columns["TABLE_NAME"], columns1.Columns["COLUMN_NAME"] };

            dataSet1.Relations.Add(new DataRelation("TablesColumns", dataSet1.Tables["tables1"].Columns["TABLE_NAME"], dataSet1.Tables["columns1"].Columns["TABLE_NAME"]));

            bindingSourceTables1.DataSource = dataSet1;
            bindingSourceTables1.DataMember = "tables1";

            bindingSourceColumns1.DataSource = bindingSourceTables1;
            bindingSourceColumns1.DataMember = "TablesColumns";

            // DataSet2
            DataTable tables2 = new DataTable("tables2");
            tables2.Columns.Add(new DataColumn("TABLE_NAME2", typeof(string)));

            DataTable columns2 = new DataTable("columns2");
            columns2.Columns.Add(new DataColumn("TABLE_NAME", typeof(string)));
            columns2.Columns.Add(new DataColumn("COLUMN_NAME2", typeof(string)));

            dataSet2.Tables.Add(tables2);
            dataSet2.Tables.Add(columns2);

            tables2.PrimaryKey = new DataColumn[] { tables2.Columns["TABLE_NAME2"] };
            columns2.PrimaryKey = new DataColumn[] { columns2.Columns["TABLE_NAME"], columns2.Columns["COLUMN_NAME2"] };

            dataSet2.Relations.Add(new DataRelation("TablesColumns", dataSet2.Tables["tables2"].Columns["TABLE_NAME2"], dataSet2.Tables["columns2"].Columns["TABLE_NAME"]));

            bindingSourceTables2.DataSource = dataSet2;
            bindingSourceTables2.DataMember = "tables2";

            bindingSourceColumns2.DataSource = bindingSourceTables2;
            bindingSourceColumns2.DataMember = "TablesColumns";

            DataGridViewComboBoxColumn dccTables = new DataGridViewComboBoxColumn()
            {
                DataSource = bindingSourceTables2,
                DataPropertyName = "TABLE_NAME2",
                DisplayMember = "TABLE_NAME2",
                ValueMember = "TABLE_NAME2",
                HeaderText = "TABLE_NAME2",
                Name = "TABLE_NAME2"
            };

            dataGridView1.Columns.Remove("TABLE_NAME2");
            dataGridView1.Columns.Add(dccTables);

            DataGridViewComboBoxColumn dccColumns = new DataGridViewComboBoxColumn()
            {
                DataSource = bindingSourceColumns2,
                DataPropertyName = "COLUMN_NAME2",
                DisplayMember = "COLUMN_NAME2",
                ValueMember = "COLUMN_NAME2",
                HeaderText = "COLUMN_NAME2",
                Name = "COLUMN_NAME2"
            };

            dataGridView2.Columns.Remove("COLUMN_NAME2");
            dataGridView2.Columns.Add(dccColumns);

            //Data
            CreateData();

        }

        private void CreateData()
        {
            for (int i = 0; i < 3; i++)
            {
                DataRow dt = dataSet1.Tables["tables1"].NewRow();
                dt["TABLE_NAME"] = "TableName" + i;
                dataSet1.Tables["tables1"].Rows.Add(dt);

                for (int j = 0; j < 5; j++)
                {
                    DataRow dc = dataSet1.Tables["columns1"].NewRow();
                    dc["TABLE_NAME"] = "TableName" + i;
                    dc["COLUMN_NAME"] = "ColumnName" + i + j;
                    dataSet1.Tables["columns1"].Rows.Add(dc);
                }
            }
            for (int i = 0; i < 3; i++)
            {
                DataRow dt = dataSet2.Tables["tables2"].NewRow();
                dt["TABLE_NAME2"] = "TableName" + i;
                dataSet2.Tables["tables2"].Rows.Add(dt);

                for (int j = 0; j < 5; j++)
                {
                    DataRow dc = dataSet2.Tables["columns2"].NewRow();
                    dc["TABLE_NAME"] = "TableName" + i;
                    dc["COLUMN_NAME2"] = "ColumnName" + i + j;
                    dataSet2.Tables["columns2"].Rows.Add(dc);
                }
            }
        }

        private void SetGrids(DataGridView dgv1, DataGridView dgv2)
        {
            dgv1.Width = 400;
            dgv2.Width = 400;
            dgv2.Top = dgv1.Height;

            this.Controls.Add(dataGridView1);
            this.Controls.Add(dataGridView2);
        }

    }
}

这个问题已经困扰我好几天了,当我终于提出这个问题时...我找到了答案。

不出所料,答案很简单。我在这篇文章中找到了灵感 How to: Ensure Multiple Controls Bound to the Same Data Source Remain Synchronized

我的解决方案是在 bindingSourceTables1 的 CurrentChanged 事件中添加这段代码:

    private void bindingSourceTables1_CurrentChanged(object sender, EventArgs e)
    {
        bindingSourceTables2.Position = bindingSourceTables2.Find("TABLE_NAME2", ((DataRowView)((BindingSource)sender).Current).Row["TABLE_NAME2"]);
    }