views:

2788

answers:

2

How do you access the items collection of a combo box in a specific row in a DataGridView?

I'm populating the combo as follows:

          Dim VATCombo As New DataGridViewComboBoxColumn
            With VATCombo
                .HeaderText = "VAT Rate"
                .Name = .HeaderText
                Dim VATCol As New JCVATRateCollection

                VATCol.LoadAll(EntitySpaces.Interfaces.esSqlAccessType.StoredProcedure)
                For Each Rate As JCVATRate In VATCol
                    .Items.Add(Rate.str.VATRate)
                Next
                .Sorted = True

                VATCol = Nothing

                .ToolTipText = "Select VAT Rate"
                .AutoSizeMode = DataGridViewAutoSizeColumnMode.DisplayedCells
                .CellTemplate.Style.BackColor = Color.Honeydew
                .DisplayIndex = 8
                .AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill

            End With
            .Columns.Add(VATCombo)
            VATCombo = Nothing

I want to be able to set a default value for each new line added to the grid, I also want to be able to change the values in the combo based on other business logic. I realise I can just set the cell value directly but I want to avoid hard-coding the values into the system and rely on the database to populate.

I'm sure it must be straight-forward but it's eluding me.....

A: 

Could you not directly cast the control within the cell using the row index to access the current row?

thismat
+1  A: 

The problem with the basic combobox in EditGridView is that all rows share the same combobox, so you cannot change it.

You to create a new class (ComboEditingControl) inherited from the ComboBox and implementing IDataGridViewEditingControl:

(e.g. customdropdown.vb:) Imports System.Collections.Generic Imports System.Drawing Imports System.Windows.Forms

Friend Class ComboEditingControl Inherits ComboBox Implements IDataGridViewEditingControl

Private dataGridViewControl As DataGridView
Private valueIsChanged As Boolean = False
Private rowIndexNum As Integer
Private ItemSelected As String

Public Sub New()
    Me.DropDownStyle = ComboBoxStyle.DropDownList
End Sub


Public Property EditingControlFormattedValue() As Object _
    Implements IDataGridViewEditingControl.EditingControlFormattedValue

    Get
        Return ItemSelected
    End Get

    Set(ByVal value As Object)
        If TypeOf value Is Decimal Then
            Me.SelectedItem = value.ToString()
        End If
    End Set
End Property


Public Function GetEditingControlFormattedValue(ByVal context As DataGridViewDataErrorContexts) As Object _
    Implements IDataGridViewEditingControl.GetEditingControlFormattedValue
    Return ItemSelected
End Function

Public ReadOnly Property EditingControlCursor() As Cursor _
    Implements IDataGridViewEditingControl.EditingPanelCursor
    Get
        Return MyBase.Cursor
    End Get
End Property

Public Sub ApplyCellStyleToEditingControl(ByVal dataGridViewCellStyle As DataGridViewCellStyle) _
    Implements IDataGridViewEditingControl.ApplyCellStyleToEditingControl

    Me.Font = dataGridViewCellStyle.Font
    Me.ForeColor = dataGridViewCellStyle.ForeColor
    Me.BackColor = dataGridViewCellStyle.BackColor

End Sub

Public Property EditingControlRowIndex() As Integer _
    Implements IDataGridViewEditingControl.EditingControlRowIndex

    Get
        Return rowIndexNum
    End Get
    Set(ByVal value As Integer)
        rowIndexNum = value
    End Set

End Property

Public Function EditingControlWantsInputKey(ByVal key As Keys, ByVal dataGridViewWantsInputKey As Boolean) As Boolean _
    Implements IDataGridViewEditingControl.EditingControlWantsInputKey

    ' Let the DateTimePicker handle the keys listed.
    Select Case key And Keys.KeyCode
        Case Keys.Up, Keys.Down, Keys.Home, Keys.End, Keys.PageDown, Keys.PageUp
            Return True
        Case Else
            Return False
    End Select
End Function

Public Sub PrepareEditingControlForEdit(ByVal selectAll As Boolean) _
    Implements IDataGridViewEditingControl.PrepareEditingControlForEdit
    ' No preparation needs to be done.
End Sub

Public ReadOnly Property RepositionEditingControlOnValueChange() As Boolean Implements _
    IDataGridViewEditingControl.RepositionEditingControlOnValueChange
    Get
        Return False
    End Get
End Property

Public Property EditingControlDataGridView() As DataGridView _
    Implements IDataGridViewEditingControl.EditingControlDataGridView

    Get
        Return dataGridViewControl
    End Get
    Set(ByVal value As DataGridView)
        dataGridViewControl = value
    End Set

End Property

Public Property EditingControlValueChanged() As Boolean _
    Implements IDataGridViewEditingControl.EditingControlValueChanged

    Get
        Return valueIsChanged
    End Get
    Set(ByVal value As Boolean)
        valueIsChanged = value
    End Set
End Property


''' <summary>
''' Notify the DataGridView that the contents of the cell have changed.
''' </summary>
''' <param name="eventargs"></param>
''' <remarks></remarks>
Protected Overrides Sub OnSelectedIndexChanged(ByVal eventargs As EventArgs)
    valueIsChanged = True
    dataGridViewControl.NotifyCurrentCellDirty(True)
    MyBase.OnSelectedItemChanged(eventargs)
    ItemSelected = SelectedItem.ToString()
End Sub

End Class


2 more classes, note in the InitializeEditingControl you need to build the items for the specific rows that you are on

Friend Class ComboColumn
    Inherits DataGridViewColumn

    Public Sub New()
        MyBase.New(New ComboCell())
    End Sub

    Public Overrides Property CellTemplate() As DataGridViewCell
        Get
            Return MyBase.CellTemplate
        End Get
        Set(ByVal value As DataGridViewCell)
            ' Ensure that the cell used for the template is a ComboCell.
            If Not (value Is Nothing) AndAlso Not value.GetType().IsAssignableFrom(GetType(ComboCell)) Then
                Throw New InvalidCastException("Must be a ComboCell")
            End If
            MyBase.CellTemplate = value
        End Set
    End Property
End Class

Friend Class ComboCell
    Inherits DataGridViewTextBoxCell

    Public Sub New()
    End Sub

    Public Overrides Sub InitializeEditingControl(ByVal rowIndex As Integer, ByVal initialFormattedValue As Object, ByVal dataGridViewCellStyle As DataGridViewCellStyle)
        ' Set the value of the editing control to the current cell value.
        MyBase.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle)

        Dim ctl As ComboEditingControl = CType(DataGridView.EditingControl, ComboEditingControl)

        Dim GetValueFromRowToUseForBuildingCombo As String = Me.DataGridView.Rows(rowIndex).Cells(0).Value.ToString()

        ctl.Items.Clear()
        For Each thing As String In ACollection
            ctl.Items.Add(Sheet)
        Next


        If Me.Value Is Nothing Then
            ctl.SelectedIndex = -1
        Else
            ctl.SelectedItem = Me.Value
        End If
    End Sub

    Public Overrides ReadOnly Property EditType() As Type
        Get
            Return GetType(ComboEditingControl)
        End Get
    End Property

    Public Overrides ReadOnly Property ValueType() As Type
        Get
            Return GetType(String)
        End Get
    End Property

    Public Overrides ReadOnly Property FormattedValueType() As System.Type
        Get
            Return GetType(String)
        End Get
    End Property

    Public Overrides ReadOnly Property DefaultNewRowValue() As Object
        Get
            Return ""
        End Get
    End Property
End Class

finally in the OnLoad code of your form, programatically add the control to the Grid:

Dim c As New ComboColumn c.HeaderText = "Sheet" c.DataPropertyName = "My Combo" c.ToolTipText = "Select something from my combo" MyDataGridView.Columns.Add(c)

To Get & Set just use the ThisRow.Cells(ComboCol).Value

The first field is generic, the other inherit and have the custom code for each DataGridView that you need HTH

GalleySlave
So can you not access the items collection once the column has been added to the gridview with a standard combo? Whichever way I try to reference it I get a string although I have actually added an object with two properties (ID and display value). How else can you handle primary keys?
Simon