Home > OS >  DataGridView column of arbitrary controls per row (or replicate that appearance)
DataGridView column of arbitrary controls per row (or replicate that appearance)

Time:09-21

I have a DataGridView which contains, among other things, a "Feature" column and a "Value" column. The "Feature" column is a DataGridViewComboBoxColumn. What I would like to do, is manipulate the "Value" column, such that it can be one of a number of controls, depending on the item selected in the "Feature" column on any given row. So, for example :

Feature Value Cell Behaviour
A Combobox with a pre-determined set of options, specific to Feature A
B Combobox with a different set of pre-determined options, specific to Feature B
C Checkbox
D Textbox (free-format)
X etc. etc.

My initial naive approach to this (which I never really expected to work but figured I'd try anyway...) was to programmatically manipulate the specific value cell in the grid whenever the Feature combobox on the same row was changed :

Private Sub dgv_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles dgv.CellValueChanged
    Dim changedCell As DataGridViewCell = CType(dgv.Rows(e.RowIndex).Cells(e.ColumnIndex), DataGridViewCell)
    If changedCell.ColumnIndex = cboFeatureColumn.Index Then
        Dim cboChangedFeature = CType(changedCell, DataGridViewComboBoxCell)
        If cboChangedFeature.Value IsNot Nothing Then ConfigureValueField(cboChangedFeature)
    End If
End Sub

Private Sub ConfigureValueField(cboFeature As DataGridViewComboBoxCell)
    Dim cllValueField As DataGridViewCell = dgv.Rows(cboFeature.RowIndex).Cells(valueColumn.Index)
    Dim featureID As Integer = dgv.Rows(cboFeature.RowIndex).Cells(featureIDColumn.Index).Value
    Dim matches = From row In dtbFeatureList Let lookupID = row.Field(Of Integer)("ID") Where lookupID = featureID
    Dim strFieldControl As String = ""
    If matches.Any Then strFeatureControl = matches.First().row.Field(Of String)("FieldControl")
    Select Case strFieldControl
        Case "Checkbox"
            ' Do something

        Case "Textbox"
            ' Do something

        Case "Combobox"
            Dim cboConfigured As New DataGridViewComboBoxCell
            Dim dvOptions As New DataView(dtbFeatureValueList)
            dvOptions.RowFilter = "[FeatureID] = " & featureID
            Dim dtbOptions As DataTable
            dtbOptions = dvOptions.ToTable
            With cboConfigured
                .DataSource = dtbOptions
                .ValueMember = "Value"
                .DisplayMember = "ValueText"
                .DisplayStyle = DataGridViewComboBoxDisplayStyle.ComboBox
                .ReadOnly = False
            End With
            cllValueField = cboConfigured
    End Select
End Sub

But this (probably, obviously to many) doesn't work; for starters it throws a DataError Default Error Dialog :

The following exception occurred in the DataGridView: System.FormatException: DataGridViewComboBoxCell value is not valid To replace this default dialog please handle the DataError event.

...which I can trap and handle (i.e. ignore!) easily enough :

Private Sub dgv_DataError(sender As Object, e As DataGridViewDataErrorEventArgs) Handles dgv.DataError
    e.Cancel = True
End Sub

...and the resulting cell does have the appearance of a combobox but nothing happens when I click the dropdown (no list options appear) I suspect there are a whole host of DataErrors being thrown; to be quite honest, I'm not entirely comfortable with ignoring exceptions like this without handling them properly...

The only alternative option I can think of is to add separate columns for each possible value type (so add a DataGridViewComboBoxColumn for combos, a DataGridViewCheckBoxColumn for checkboxes, a DataGridViewTextBoxColumn for textboxes etc.) but then all of my values are scattered across multiple columns instead of all under a single heading which will be really confusing to look at.

And I really want to retain the appearance of comboboxes (set list of options) versus checkboxes (boolean values) versus textboxes (free-format text), as it makes it a lot easier for users to differentiate the values.

I read somewhere that it may be possible to derive my own custom column class, inheriting the native DataGridViewColumn class, but I couldn't find any examples of how this was done. I've done something similar with a customised DataGridViewButtonColumn but literally just to change the appearance of the buttons across the entire column, not the functionality of the individual cells within it.

Would anybody have any suggestions as to how it might be possible to have a mix of controls in the same column, configured specifically to the row in which they reside?

EDIT

So, I followed the walkthrough at : SOSO73734207

  • Related