如何根据第一个 GridViewComboBoxColumn 的选择填充第二个列

Posted

技术标签:

【中文标题】如何根据第一个 GridViewComboBoxColumn 的选择填充第二个列【英文标题】:how to fill second Column according to selection of first GridViewComboBoxColumn 【发布时间】:2013-06-08 19:02:10 【问题描述】:

我有两个 DataGridViewComboBoxColumn。我想根据第一个 GridViewComboBoxColumn 的选择填充第二列。我在第一个 Combobox 中有组,在第二个 Combobox 中有服务。我希望当我选择 group1 时,只有 group1 的服务显示在服务组合框中。 我正在使用存储过程。

var groupColumn = new DataGridViewComboBoxColumn();

                DataTable dtcategori = cb.GetAllDataCategori();
                groupColumn.Name = "Group";
                groupColumn.HeaderText = Resources.GroupName;
                groupColumn.DataSource = dtcategori;
                groupColumn.ValueMember = "ID";
                groupColumn.DisplayMember = "Name";
                groupColumn.Width = 100;
                this.DataGridViewFactor.Columns.Add(groupColumn);

                var serviceColumn = new DataGridViewComboBoxColumn();
                    //var categoriId = Convert.ToInt32(groupColumn.);
                // DataTable dtServices = sb.ServiceGetById(categoriId);
                    DataTable dtServices = sb.GetAllDataServices();
                    serviceColumn.Name = "Services";
                    serviceColumn.HeaderText = Resources.Service;
                    serviceColumn.DataSource = dtServices;
                    serviceColumn.ValueMember = "ID";
                    serviceColumn.DisplayMember = "Name";
                    serviceColumn.Width = 100;

                    this.DataGridViewFactor.Columns.Add(serviceColumn);

【问题讨论】:

您的要求似乎很正常,但有一种情况使其不稳定:当您将 DataGridViewComboBoxColumn DataSource 绑定到 DataTable 时,每行中的所有 ComboBoxes 将使用相同的 DataSource,假设此 DataSource 有 4项目:1,2,3,4。如果您从 Column1 中选择并使 DataSource 仅保留 1,2 但还有其他行在 Column2 中具有值为 3 和 4 的单元格,该怎么办?这些单元格将不会显示。您知道ComboBox 的工作原理,如果该值不在其Items 列表中,则不会显示该值。这就是为什么我尝试解决这个问题但并不容易。 【参考方案1】:

哇,我花了大约 2 个小时才找到这个答案,虽然不好但有用且有帮助:)

首先,您必须将 groupColumn.DataSource 更改为 BindingSource 而不是代码中的 DataTable,因为当您从 groupColumn 的组合框中选择项目时,您需要一些 PositionChanged 事件来通知.你知道DataGridViewColumn 没有任何SelectedIndexChanged 事件。其次,我看不出你的GroupServices 之间有什么关系,Services 的数据源应该有一个类似GroupID 的字段,这样你就可以在两列之间链接。我想有这样一个GroupID 字段。你的Services 有一个ID,但我不确定是不是GroupID,可能是你的ServiceID

推荐:我认为您应该将您的 groupColumn'sserviceColumn's DisplayStyle 更改为 DataGridViewComboBoxDisplayStyle.Nothing - 我觉得最好。

我想在代码旁边的评论中解释我的解决方案。代码如下:

//Your code is modified a little.
var groupColumn = new DataGridViewComboBoxColumn();
groupColumn.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing;
DataTable dtcategori = cb.GetAllDataCategori();
groupColumn.Name = "Group";
groupColumn.HeaderText = Resources.GroupName;
//Create a BindingSource from your DataTable
BindingSource bs = new BindingSource(dtcategori,"");
groupColumn.DataSource = bs;
bs.PositionChanged += (s,e) => 
   //Filter for items which have the selected GroupID
   ((DataTable)((DataGridViewComboBoxColumn)DataGridViewFactor.Columns["Services"]).DataSource).DefaultView.RowFilter =
                string.Format("GroupID='0'",((DataRowView)bs.Current).Row["ID"]);
   //Set the initial value of the corresponding cell in serviceColumn
   DataGridViewFactor.CurrentRow.Cells["Services"].Value = ((DataTable)((DataGridViewComboBoxColumn)DataGridViewFactor.Columns["Services"]).DataSource).DefaultView.ToTable().Rows[0]["Name"];
;
//-------------------------------------------
groupColumn.ValueMember = "ID";
groupColumn.DisplayMember = "Name";
groupColumn.Width = 100;
this.DataGridViewFactor.Columns.Add(groupColumn);

var serviceColumn = new DataGridViewComboBoxColumn();
serviceColumn.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing;
//var categoriId = Convert.ToInt32(groupColumn.);
// DataTable dtServices = sb.ServiceGetById(categoriId);
DataTable dtServices = sb.GetAllDataServices();
serviceColumn.Name = "Services";
serviceColumn.HeaderText = Resources.Service;
serviceColumn.DataSource = dtServices;
serviceColumn.ValueMember = "ID";
serviceColumn.DisplayMember = "Name";
serviceColumn.Width = 100;

this.DataGridViewFactor.Columns.Add(serviceColumn);

//Because filtering this way can make some cell have a value which is not contained in 
//the DataGridViewComboBoxColumn.Items, we have to handle the DataError
private void DataGridViewFactor_DataError(object sender, DataGridViewDataErrorEventArgs e)
    //We're interested only in DataGridViewComboBoxColumn
    if(DataGridViewFactor.Columns[e.ColumnIndex] is DataGridViewComboBoxColumn)
        e.Cancel = true;
    

//Because when you filter on a row, the DataGridViewComboBoxColumn.DataSource with
//the filtered DefaultView will apply on all the rows in the same 
//DataGridViewComboBoxColumn, we have to apply the filter for each row if it is selected
private void DataGridViewFactor_SelectionChanged(object sender, EventArgs e)
            
        ((DataTable)((DataGridViewComboBoxColumn)DataGridViewFactor.Columns["Services"]).DataSource).DefaultView.RowFilter =
           string.Format("GroupID='0'", DataGridViewFactor.CurrentRow.Cells["Group"].Value);            

//Because when you filter on a row, the DataSource DefaultView of the groupColumn will
//be changed (limited to fewer items) and there will be cells in that column having 
//values which are not contained in the filtered items. Those cells will not be 
//displayed when you move the mouse over. This CellPainting event handler is to help 
//them look normal.
private void DataGridViewFactor_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
    if (e.RowIndex > -1 && e.ColumnIndex > -1)
    
            if (e.Value != null)
            
                e.Handled = true;
                e.PaintBackground(e.CellBounds, true);
                StringFormat sf = new StringFormat()  LineAlignment = StringAlignment.Center ;
                e.Graphics.DrawString(e.Value.ToString(), DataGridViewFactor.Font, new SolidBrush(DataGridViewFactor.ForeColor), e.CellBounds, sf);
            
    

仅此而已。

希望对你有帮助!

【讨论】:

以上是关于如何根据第一个 GridViewComboBoxColumn 的选择填充第二个列的主要内容,如果未能解决你的问题,请参考以下文章

如何根据第一个选定的项目对齐图形场景中的图形项目?

如何根据 sencha 中 json 响应的第一个组合值填充第二个组合

如何根据第二个数据帧映射第一个数据帧中的值?

如何根据字符串的第一个和第三个字符过滤一列字符串?

如何根据第一个下拉列表的选择过滤第二个下拉列表? - 角

如何根据第一个组件收到的 websocket 事件更新第二个组件中的内容?