Sunday, December 16, 2007

Dynamic ComboBox in a DataGridView

And here is the second installment. It is generally convenient to bind the grid column to a single datasource such that all dropdowns have identical items. However, certain applications require that the items in the dropdown depend upon other attributes of the row.

For this example, I will create a three column grid with the first column containing the Employee Name, the second one containing the Department and third one being the dynamic combobox column that lists the positions for the particular department.

Once again, I have created the datasources at runtime to provide a complete example. To add that dynamic feel, I have decided to handle a DataGridView event - CellValueChanged. You can of course set this value after binding the original gridview source as well.

The Setup code that declares two dummy datasources and binds the Employee datasource with the gridview.

    'Create the sample list of names

    Dim dtNames As DataTable = New DataTable

    dtNames.Columns.Add("Name", GetType(String))

    dtNames.Columns.Add("Department", GetType(String))

 

    Dim dr As DataRow

    dr = dtNames.NewRow : dr.Item("Name") = "Alvin Menezes" : dr.Item("Department") = "" : dtNames.Rows.Add(dr)

    dr = dtNames.NewRow : dr.Item("Name") = "Saikumar Chettiar" : dr.Item("Department") = "" : dtNames.Rows.Add(dr)

    dr = dtNames.NewRow : dr.Item("Name") = "Sample Name 1" : dr.Item("Department") = "" : dtNames.Rows.Add(dr)

    dr = dtNames.NewRow : dr.Item("Name") = "Sample Name 2" : dr.Item("Department") = "" : dtNames.Rows.Add(dr)

 

    'create the sample department - position choices

    dtChoices = New DataTable

    dtChoices.Columns.Add("Department", GetType(String))

    dtChoices.Columns.Add("Position", GetType(String))

 

    dr = dtChoices.NewRow : dr.Item("Department") = "IT" : dr.Item("Position") = "Tech Architect" : dtChoices.Rows.Add(dr)

    dr = dtChoices.NewRow : dr.Item("Department") = "IT" : dr.Item("Position") = "Project Manager" : dtChoices.Rows.Add(dr)

    dr = dtChoices.NewRow : dr.Item("Department") = "IT" : dr.Item("Position") = "Project Leader" : dtChoices.Rows.Add(dr)

    dr = dtChoices.NewRow : dr.Item("Department") = "IT" : dr.Item("Position") = "Developer" : dtChoices.Rows.Add(dr)

    dr = dtChoices.NewRow : dr.Item("Department") = "HR" : dr.Item("Position") = "Manager" : dtChoices.Rows.Add(dr)

    dr = dtChoices.NewRow : dr.Item("Department") = "HR" : dr.Item("Position") = "Executive" : dtChoices.Rows.Add(dr)

 

 

    'Bind the datagridview

    dgvSampleEx.AutoGenerateColumns = False

    dgvSampleEx.DataSource = dtNames



The code listing for the dynamic ComboBox rendering

  Private Sub dgvSampleEx_CellValueChanged(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dgvSampleEx.CellValueChanged

    If e.RowIndex < 0 Then

      Exit Sub

    End If

 

    If e.ColumnIndex = 1 Then

      Dim Department As String = CStr(dgvSampleEx.Rows(e.RowIndex).Cells(1).Value)

      Dim dv As DataView = New DataView(dtChoices, "Department = '" & Department & "'", "", DataViewRowState.CurrentRows)

 

      Dim dgvComboCell As DataGridViewComboBoxCell = CType(dgvSampleEx.Rows(e.RowIndex).Cells(2), DataGridViewComboBoxCell)

      With dgvComboCell

        .DisplayMember = "Position"

        .ValueMember = "Position"

        .DataSource = dv

      End With

    End If

  End Sub


Guess the trick is to know that binding a DataGridView column sets all dropdown elements to be identical whereas binding the DataGridViewCell gives you more control over the exact elements that need to be displayed in the dropdown choices.

And the results for all to see


Note how the dropdown values differ - depending on the Department that has been entered. Ideally, the Department could also be rendered as a combobox. I decided to go with plain text to keep this example simple.

No comments: