DataGridView Cascading/Dependent ComboBox Columns

To have dependent (cascading or master/slave) ComboBox columns in DataGridView, you can follow this steps:

  1. Set DataSource of slave column to all available values.

    Goal: Here the goal is prevent rendering errors at first load, so all slave combo boxes can show value correctly.

  2. Hanlde EditingControlShowing event of the grid and check if the current cell is slave combo cell, then get the editing control using e.Control which is of type DataGridViewComboBoxEditingControl. Then check the value of master combo cell and set the DataSource property of editing control to a suitable subset of values based on the value of master combo cell. If the value of master cell is null, set the data source to null.

    Goal: Here the goal is setting data source of slave combo to show only suitable values when selecting values from slave combo.

  3. Handle CellValueChanged and check if the current cell is master combo, then set the value for dependent cell to null.
    Note: Instead of setting the value of slave cell to null, you can set it to first available valid value based on master cell value.

    Goal: Here the goal is prevent the slave combo to have invalid values after the value of master combo changed, so we reset the value.

Following above rules you can have as many dependent combo boxes as you need.

Example

In below example I have a Country (Id, Name) table, a State(Id, Name, CountryId) table and a Population(CountryId, StateId, Population) table. And I want to perform data entry for Population table using 2 combo columns for country and state and a text column for population. I know this is not a normal db design, but it’s just for example of having master/slave (dependent) combo box columns in grid:

Private Sub EditingControlShowing(sender As Object, _
    e As DataGridViewEditingControlShowingEventArgs) _
    Handles PopulationDataGridView.EditingControlShowing

    Dim grid = DirectCast(sender, DataGridView)
    If (grid.CurrentCell.ColumnIndex = 1) Then 'State column
        Dim combo = DirectCast(e.Control, DataGridViewComboBoxEditingControl)
        If (grid.CurrentRow.Cells(0).Value IsNot DBNull.Value) Then
            Dim data = Me.DataSet1.State.AsDataView()
            data.RowFilter = "CountryId = " + grid.CurrentRow.Cells(0).Value.ToString()
            combo.DataSource = data
        Else
            combo.DataSource = Nothing
        End If
    End If
End Sub

Private Sub CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) _
    Handles PopulationDataGridView.CellValueChanged
    Dim grid = DirectCast(sender, DataGridView)
    If (e.ColumnIndex = 0 And e.RowIndex >= 0) Then 'Country Column
        grid.Rows(e.RowIndex).Cells(1).Value = DBNull.Value 'State Column 
    End If
End Sub

Leave a Comment