VBobCat
Well-known member
I have this custom Control class, derived from ComboBox. Its purpose is to provide a standard behavior for controls whose list of items will be populated depending on what user types in it as search criteria.
These controls are working as expected, but now I would like my DataGridViews to host cells that behaved just like these. I tried to follow an example I found on web and wrote those classes below. However, it never worked. It raises the same exception in DataGridView's standard erro dialog, once when it is loaded and again repeats forever whenever I try to click it: System.FormatException: The property FormattedValueType of a cell cannot be null.
Any help you guys could give me, or directions for properly implementing this, will be deeply appreciated. Thanks!
Imports System.ComponentModel
Public Class SearchBox
Inherits ComboBox
Private hasTextChanged As Boolean
Private _queryInterval As Integer = 3000
Public Property QueryInterval As Integer
Get
Return _queryInterval
End Get
Set(value As Integer)
_queryInterval = value
If _myTimer IsNot Nothing Then _myTimer.Interval = value
End Set
End Property
Private WithEvents _myTimer As Timer
Private ReadOnly Property MyTimer As Timer
Get
If _myTimer Is Nothing Then
_myTimer = New Timer() With {.Enabled = False, .Interval = QueryInterval}
End If
Return _myTimer
End Get
End Property
Private WithEvents _myPictureBox As PictureBox
Private ReadOnly Property MyPictureBox As PictureBox
Get
If _myPictureBox Is Nothing Then
_myPictureBox = New PictureBox() With {
.BackColor = Color.Transparent,
.BorderStyle = BorderStyle.None,
.Parent = Me,
.Height = Height - 2,
.Width = Height - 2,
.Top = 1,
.Left = Width - Height,
.Visible = False,
.SizeMode = PictureBoxSizeMode.CenterImage}
_myPictureBox.Image = Image.FromStream(
New IO.MemoryStream(
Convert.FromBase64String(
"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")))
End If
Return _myPictureBox
End Get
End Property
Friend Property WaitingIcon As Boolean
Get
Return MyPictureBox.Visible
End Get
Set(value As Boolean)
MyPictureBox.Visible = value
End Set
End Property
Public Shadows Property DataSource As DataTable
Get
Return MyBase.DataSource
End Get
Set(value As DataTable)
MyBase.DataSource = value
End Set
End Property
Public Shadows Property SelectedItem As DataRowView
Get
Return MyBase.SelectedItem
End Get
Set(value As DataRowView)
MyBase.SelectedItem = value
End Set
End Property
Private Sub _myTimer_Tick(sender As Object, e As EventArgs) Handles _myTimer.Tick
MyTimer.Stop()
SendKeys.Send("{TAB}")
End Sub
Protected Overrides Sub OnKeyDown(e As KeyEventArgs)
MyTimer.Stop()
If e.KeyValue = 13 Then e.SuppressKeyPress = True
MyBase.OnKeyDown(e)
End Sub
Protected Overrides Sub OnKeyUp(e As KeyEventArgs)
If e.KeyValue = 13 Then e.SuppressKeyPress = True
MyBase.OnKeyUp(e)
If e.KeyValue = 13 Then
SendKeys.Send("{TAB}")
ElseIf hasTextChanged
hasTextChanged = False
MyTimer.Stop()
MyTimer.Start()
End If
End Sub
Protected Overrides Sub OnTextChanged(e As EventArgs)
hasTextChanged = True
MyBase.OnTextChanged(e)
End Sub
Protected WithEvents BGW As New BackgroundWorker
Private work As Action, whenDone As Action
Protected Sub DoAction(ByVal work As Action, whendone As Action)
Me.work = work
Me.whenDone = whendone
BGW.RunWorkerAsync()
End Sub
Private Sub BGW_DoWork(sender As Object, e As DoWorkEventArgs) Handles BGW.DoWork
Invoke(Sub() WaitingIcon = True)
If work IsNot Nothing Then work.Invoke
End Sub
Private Sub BGW_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BGW.RunWorkerCompleted
Invoke(Sub() WaitingIcon = False)
If whenDone IsNot Nothing Then BeginInvoke(whenDone)
End Sub
End Class
These controls are working as expected, but now I would like my DataGridViews to host cells that behaved just like these. I tried to follow an example I found on web and wrote those classes below. However, it never worked. It raises the same exception in DataGridView's standard erro dialog, once when it is loaded and again repeats forever whenever I try to click it: System.FormatException: The property FormattedValueType of a cell cannot be null.
Public Class SearchColumn
Inherits DataGridViewColumn
Public Sub New()
MyBase.New(New SearchCell())
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(SearchCell)) _
Then
Throw New InvalidCastException("Must be a SearchCell")
End If
MyBase.CellTemplate = value
End Set
End Property
End Class
Public Class SearchCell
Inherits DataGridViewCell
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 SearchEditingControl =
CType(DataGridView.EditingControl, SearchEditingControl)
' Use the default row value when Value property is null.
If (Me.Value Is Nothing) Then
ctl.Text = CStr(Me.DefaultNewRowValue).Assert
Else
ctl.Text = CStr(Me.Value).Assert
End If
End Sub
End Class
Class SearchEditingControl
Inherits PessBox
Implements IDataGridViewEditingControl
Private dataGridViewControl As DataGridView
Private valueIsChanged As Boolean = False
Private rowIndexNum As Integer
Public Property EditingControlDataGridView As DataGridView Implements IDataGridViewEditingControl.EditingControlDataGridView
Get
Return dataGridViewControl
End Get
Set(value As DataGridView)
dataGridViewControl = value
End Set
End Property
Public Property EditingControlFormattedValue As Object Implements IDataGridViewEditingControl.EditingControlFormattedValue
Get
Return Me.Text.Assert
End Get
Set(value As Object)
Me.Text = CStr(value).Assert
End Set
End Property
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 Property EditingControlValueChanged As Boolean Implements IDataGridViewEditingControl.EditingControlValueChanged
Get
Return valueIsChanged
End Get
Set(value As Boolean)
valueIsChanged = 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
Me.Font = dataGridViewCellStyle.Font
Me.ForeColor = dataGridViewCellStyle.ForeColor
Me.BackColor = dataGridViewCellStyle.BackColor
End Sub
Public Sub PrepareEditingControlForEdit(selectAll As Boolean) Implements IDataGridViewEditingControl.PrepareEditingControlForEdit
' No preparation needs to be done.
End Sub
Public Function EditingControlWantsInputKey(keyData As Keys, dataGridViewWantsInputKey As Boolean) As Boolean Implements IDataGridViewEditingControl.EditingControlWantsInputKey
Select Case keyData And Keys.KeyCode
Case Keys.Left, Keys.Up, Keys.Down, Keys.Right, Keys.Home, Keys.End, Keys.PageDown, Keys.PageUp
Return True
Case Else
Return Not dataGridViewWantsInputKey
End Select
End Function
Public Function GetEditingControlFormattedValue(context As DataGridViewDataErrorContexts) As Object Implements IDataGridViewEditingControl.GetEditingControlFormattedValue
Return Me.Text.Assert
End Function
Protected Overrides Sub OnTextChanged(e As EventArgs)
valueIsChanged = True
Me.EditingControlDataGridView.NotifyCurrentCellDirty(True)
MyBase.OnTextChanged(e)
End Sub
End Class
Any help you guys could give me, or directions for properly implementing this, will be deeply appreciated. Thanks!