RobertAlanGustafsonII
Member
- Joined
- Sep 16, 2023
- Messages
- 20
- Programming Experience
- 10+
WHAT I HAVE:
Visual Basic 2019, .NET Framwork 4.0+, WinForms
MY ISSUE:
I've read the help topic "How to: Host Controls in Windows Forms DataGridView Cells", which shows how to host a DateTimePicker control in a cell via having a class that derives from it and implements IDataGridViewEditingControl, and having classes that derive from DataGridViewColumn and DataGridViewCell. I've since tried to rework the code to host a custom control I've created, ExtComboBox. (I know there's a column type for the standard combo box, but here I need my custom control!)
The code below has an InformationColumn class that derives from DataGridViewColumn and an InformationCell class that derives from DataGridViewTextCell (similar to the help example). It then has an InformationSelectionControl class that derives from ExtComboBox (my custom control type) and implements IDataGridViewEditingControl. I've tried to follow the provided help example as closely as possible while making the changes needed to accommodate a different kind of control being hosted.
The problem occurs when I try to add an InformationColumn at design time (after a build). Any such columns I add disappear (!!) from the grid as soon as I exit the Add Columns dialog. Also, if I, using Edit Colmuns, try to change a column to InformationColumn type, it tells me that the property change isn't valid (it says "object not set to a reference", and gives me no ability to trace the error to the offended statement [or lack of a statement]). Is it not possible to add a column hosting a custom control at design time, or am I doing something wrong?! In general, is there anything in the code below that would keep the column from being properly added at run-time?
Code as follows:
Please give any answers and corrections ASAP, in VB.NET, and as simply as possible. (BTW, Residence is a type defined elsewhere in my project.)
Visual Basic 2019, .NET Framwork 4.0+, WinForms
MY ISSUE:
I've read the help topic "How to: Host Controls in Windows Forms DataGridView Cells", which shows how to host a DateTimePicker control in a cell via having a class that derives from it and implements IDataGridViewEditingControl, and having classes that derive from DataGridViewColumn and DataGridViewCell. I've since tried to rework the code to host a custom control I've created, ExtComboBox. (I know there's a column type for the standard combo box, but here I need my custom control!)
The code below has an InformationColumn class that derives from DataGridViewColumn and an InformationCell class that derives from DataGridViewTextCell (similar to the help example). It then has an InformationSelectionControl class that derives from ExtComboBox (my custom control type) and implements IDataGridViewEditingControl. I've tried to follow the provided help example as closely as possible while making the changes needed to accommodate a different kind of control being hosted.
The problem occurs when I try to add an InformationColumn at design time (after a build). Any such columns I add disappear (!!) from the grid as soon as I exit the Add Columns dialog. Also, if I, using Edit Colmuns, try to change a column to InformationColumn type, it tells me that the property change isn't valid (it says "object not set to a reference", and gives me no ability to trace the error to the offended statement [or lack of a statement]). Is it not possible to add a column hosting a custom control at design time, or am I doing something wrong?! In general, is there anything in the code below that would keep the column from being properly added at run-time?
Code as follows:
ExtComboBox control hosted in DataGridView cell:
Public Class InformationColumn
Inherits DataGridViewColumn
Public Sub New()
MyBase.New(New InformationCell())
End Sub
Public Overrides Property CellTemplate() As DataGridViewCell
Get
Return MyBase.CellTemplate
End Get
Set(value As DataGridViewCell)
If value IsNot Nothing _
AndAlso Not value.GetType.IsAssignableFrom(GetType(InformationCell)) Then
Throw New InvalidCastException("Cell must be of InformationCell type!")
End If
MyBase.CellTemplate = value
End Set
End Property
End Class
Public Class InformationCell
Inherits DataGridViewTextBoxCell
Dim InformationSelectionControl As InformationSelectionControl
Public Sub New()
' MyBase.New()
With Me.Style
.NullValue = "" : .Format = ""
.Alignment = DataGridViewContentAlignment.MiddleCenter
Dim Column As DataGridViewColumn = Me.OwningColumn, _
ColumnFont As Font = Column.DefaultCellStyle.Font
Select Case Column.Name
Case "dgvc" & NameOf(Residence)
' 2 lines per entry
.Font = New Font(ColumnFont.FontFamily, ColumnFont.SizeInPoints * 2F)
Case Else
' 1 line per entry
.Font = ColumnFont
End Select
End With
End Sub
Public Overrides ReadOnly Property EditType() As Type
Get
Return GetType(InformationSelectionControl)
End Get
End Property
Public Overrides ReadOnly Property DefaultNewRowValue() As Object
Get
Return ""
End Get
End Property
Public Overrides ReadOnly Property ValueType() As Type
Get
Return GetType(String)
End Get
End Property
Public Overrides Sub InitializeEditingControl(ByVal RowIndex As Integer, _
ByVal InitialFormattedValue As Object, ByVal DataGridViewCellStyle As DataGridViewCellStyle)
MyBase.InitializeEditingControl(RowIndex, InitialFormattedValue, DataGridViewCellStyle)
With Me.DataGridView
MyBase.InitializeEditingControl(RowIndex, _
InitialFormattedValue, DataGridViewCellStyle)
Dim isc As InformationSelectionControl = _
DirectCast(.EditingControl, InformationSelectionControl)
If Not isc.DroppedDown Then
' force filling of list
isc.DroppedDown = True : isc.DroppedDown = False
End If
If Me.Value Is Nothing Then
isc.SelectedIndex = -1
Else
isc.SelectedIndex = isc.FindStringExact(Me.Value.ToString)
End If
End With
End Sub
Protected Overrides Function GetValue(rowIndex As Integer) As Object
With Me.DataGridView
Dim isc As InformationSelectionControl = _
DirectCast(.EditingControl, InformationSelectionControl)
Return isc.SelectedItem.ToString
End With
End Function
Protected Overrides Function SetValue(rowIndex As Integer, value As Object) As Boolean
With Me.DataGridView
Dim isc As InformationSelectionControl = _
DirectCast(.EditingControl, InformationSelectionControl)
If value Is Nothing Then
isc.SelectedIndex = -1
Else
isc.SelectedIndex = isc.FindStringExact(Me.Value.ToString)
End If
Return isc.SelectedIndex > -1
End With
End Function
End Class
Public Class InformationSelectionControl
Inherits ExtComboBox
Implements IDataGridViewEditingControl
Private dgvControl As DataGridView
Private IsValueChanged As Boolean = False
Private RowIndex As Integer
Public Sub New()
MyBase.New()
Me.DropDownHorizontalScrollbar = True : Me.DropDownHorizontalExtent = -1
Me.DropDownStyle = ComboBoxStyle.DropDownList
End Sub
Public Property EditingControlDataGridView As DataGridView _
Implements IDataGridViewEditingControl.EditingControlDataGridView
Get
Return dgvControl
End Get
Set(value As DataGridView)
dgvControl = value
End Set
End Property
Public Property EditingControlFormattedValue() As Object _
Implements IDataGridViewEditingControl.EditingControlFormattedValue
Get
Return Me.SelectedItem.ToString
End Get
Set(value As Object)
Me.SelectedIndex = Me.FindStringExact(value.ToString)
End Set
End Property
Public Property EditingControlRowIndex() As Integer _
Implements IDataGridViewEditingControl.EditingControlRowIndex
Get
Return RowIndex
End Get
Set(value As Integer)
RowIndex = value
End Set
End Property
Public Property EditingControlValueChanged() As Boolean _
Implements IDataGridViewEditingControl.EditingControlValueChanged
Get
Return IsValueChanged
End Get
Set(value As Boolean)
IsValueChanged = value
End Set
End Property
Public ReadOnly Property EditingPanelCursor() As Cursor _
Implements IDataGridViewEditingControl.EditingPanelCursor
Get
Return MyBase.Cursor
End Get
End Property
Public ReadOnly Property RepositionEditingControlOnValueChange() As Boolean _
Implements IDataGridViewEditingControl.RepositionEditingControlOnValueChange
Get
Return False
End Get
End Property
Public Sub ApplyCellStyleToEditingControl(dataGridViewCellStyle As DataGridViewCellStyle) _
Implements IDataGridViewEditingControl.ApplyCellStyleToEditingControl
With dataGridViewCellStyle
Me.Font = .Font : Me.ForeColor = .ForeColor : Me.BackColor = .BackColor
End With
Exit Sub
With dataGridViewCellStyle
Me.Font = New Font(.Font.FontFamily.Name, 9.0F, .Font.Style)
Me.ForeColor = .ForeColor : Me.BackColor = .BackColor
End With
With Me.EditingControlDataGridView
Me.DrawMode = ExtListAndCombo.DrawMode.UseVariableHeight
Dim Cell As DataGridViewCell = .CurrentCell
If Cell IsNot Nothing AndAlso Cell.OwningColumn IsNot Nothing Then
Select Case Cell.OwningColumn.Name
Case "dgvc" & NameOf(Residence)
' 2 lines per entry
Me.Font = New Font(Me.Font.FontFamily, Me.Font.SizeInPoints * 2F)
End Select
End If
End With
End Sub
Public Sub PrepareEditingControlForEdit(selectAll As Boolean) _
Implements IDataGridViewEditingControl.PrepareEditingControlForEdit
' no preparation needed
End Sub
Public Function EditingControlWantsInputKey(keyData As Keys, _
dataGridViewWantsInputKey As Boolean) As Boolean _
Implements IDataGridViewEditingControl.EditingControlWantsInputKey
' anything but Tab key
If (keyData And &HFFFF) <> Keys.Tab Then
Return True
Else
Return Not dataGridViewWantsInputKey
End If
End Function
Public Function GetEditingControlFormattedValue(context As DataGridViewDataErrorContexts) As Object _
Implements IDataGridViewEditingControl.GetEditingControlFormattedValue
Return Me.SelectedItem
End Function
Protected Overrides Sub OnSelectedIndexChanged(e As EventArgs)
IsValueChanged = True : Me.EditingControlDataGridView.NotifyCurrentCellDirty(True)
MyBase.OnSelectedIndexChanged(e)
End Sub
End Class
Please give any answers and corrections ASAP, in VB.NET, and as simply as possible. (BTW, Residence is a type defined elsewhere in my project.)
Last edited: