To have dependent (cascading or master/slave) ComboBox
columns in DataGridView
, you can follow this steps:
-
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.
-
Hanlde
EditingControlShowing
event of the grid and check if the current cell is slave combo cell, then get the editing control usinge.Control
which is of typeDataGridViewComboBoxEditingControl
. Then check the value of master combo cell and set theDataSource
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.
-
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