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.
vb Code:
  1. Imports System.ComponentModel
  2. Public Class SearchBox
  3. Inherits ComboBox
  4.  
  5. Private hasTextChanged As Boolean
  6.  
  7. Private _queryInterval As Integer = 3000
  8. Public Property QueryInterval As Integer
  9. Get
  10. Return _queryInterval
  11. End Get
  12. Set(value As Integer)
  13. _queryInterval = value
  14. If _myTimer IsNot Nothing Then _myTimer.Interval = value
  15. End Set
  16. End Property
  17.  
  18. Private WithEvents _myTimer As Timer
  19. Private ReadOnly Property MyTimer As Timer
  20. Get
  21. If _myTimer Is Nothing Then
  22. _myTimer = New Timer() With {.Enabled = False, .Interval = QueryInterval}
  23. End If
  24. Return _myTimer
  25. End Get
  26. End Property
  27.  
  28. Private WithEvents _myPictureBox As PictureBox
  29. Private ReadOnly Property MyPictureBox As PictureBox
  30. Get
  31. If _myPictureBox Is Nothing Then
  32. _myPictureBox = New PictureBox() With {
  33. .BackColor = Color.Transparent,
  34. .BorderStyle = BorderStyle.None,
  35. .Parent = Me,
  36. .Height = Height - 2,
  37. .Width = Height - 2,
  38. .Top = 1,
  39. .Left = Width - Height,
  40. .Visible = False,
  41. .SizeMode = PictureBoxSizeMode.CenterImage}
  42. _myPictureBox.Image = Image.FromStream(
  43. New IO.MemoryStream(
  44. Convert.FromBase64String(
  45. "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")))
  46. End If
  47. Return _myPictureBox
  48. End Get
  49. End Property
  50.  
  51. Friend Property WaitingIcon As Boolean
  52. Get
  53. Return MyPictureBox.Visible
  54. End Get
  55. Set(value As Boolean)
  56. MyPictureBox.Visible = value
  57. End Set
  58. End Property
  59.  
  60. Public Shadows Property DataSource As DataTable
  61. Get
  62. Return MyBase.DataSource
  63. End Get
  64. Set(value As DataTable)
  65. MyBase.DataSource = value
  66. End Set
  67. End Property
  68.  
  69. Public Shadows Property SelectedItem As DataRowView
  70. Get
  71. Return MyBase.SelectedItem
  72. End Get
  73. Set(value As DataRowView)
  74. MyBase.SelectedItem = value
  75. End Set
  76. End Property
  77.  
  78. Private Sub _myTimer_Tick(sender As Object, e As EventArgs) Handles _myTimer.Tick
  79. MyTimer.Stop()
  80. SendKeys.Send("{TAB}")
  81. End Sub
  82.  
  83. Protected Overrides Sub OnKeyDown(e As KeyEventArgs)
  84. MyTimer.Stop()
  85. If e.KeyValue = 13 Then e.SuppressKeyPress = True
  86. MyBase.OnKeyDown(e)
  87. End Sub
  88.  
  89. Protected Overrides Sub OnKeyUp(e As KeyEventArgs)
  90. If e.KeyValue = 13 Then e.SuppressKeyPress = True
  91. MyBase.OnKeyUp(e)
  92. If e.KeyValue = 13 Then
  93. SendKeys.Send("{TAB}")
  94. ElseIf hasTextChanged
  95. hasTextChanged = False
  96. MyTimer.Stop()
  97. MyTimer.Start()
  98. End If
  99. End Sub
  100.  
  101. Protected Overrides Sub OnTextChanged(e As EventArgs)
  102. hasTextChanged = True
  103. MyBase.OnTextChanged(e)
  104. End Sub
  105.  
  106. Protected WithEvents BGW As New BackgroundWorker
  107. Private work As Action, whenDone As Action
  108. Protected Sub DoAction(ByVal work As Action, whendone As Action)
  109. Me.work = work
  110. Me.whenDone = whendone
  111. BGW.RunWorkerAsync()
  112. End Sub
  113. Private Sub BGW_DoWork(sender As Object, e As DoWorkEventArgs) Handles BGW.DoWork
  114. Invoke(Sub() WaitingIcon = True)
  115. If work IsNot Nothing Then work.Invoke
  116. End Sub
  117. Private Sub BGW_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BGW.RunWorkerCompleted
  118. Invoke(Sub() WaitingIcon = False)
  119. If whenDone IsNot Nothing Then BeginInvoke(whenDone)
  120. End Sub
  121. 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.
vb Code:
  1. Public Class SearchColumn
  2. Inherits DataGridViewColumn
  3. Public Sub New()
  4. MyBase.New(New SearchCell())
  5. End Sub
  6. Public Overrides Property CellTemplate() As DataGridViewCell
  7. Get
  8. Return MyBase.CellTemplate
  9. End Get
  10. Set(value As DataGridViewCell)
  11. If (value IsNot Nothing) AndAlso
  12. Not value.GetType().IsAssignableFrom(GetType(SearchCell)) _
  13. Then
  14. Throw New InvalidCastException("Must be a SearchCell")
  15. End If
  16. MyBase.CellTemplate = value
  17. End Set
  18. End Property
  19. End Class
  20.  
  21. Public Class SearchCell
  22. Inherits DataGridViewCell
  23. Public Overrides Sub InitializeEditingControl(ByVal rowIndex As Integer,
  24. ByVal initialFormattedValue As Object,
  25. ByVal dataGridViewCellStyle As DataGridViewCellStyle)
  26.  
  27. ' Set the value of the editing control to the current cell value.
  28. MyBase.InitializeEditingControl(rowIndex, initialFormattedValue,
  29. dataGridViewCellStyle)
  30.  
  31. Dim ctl As SearchEditingControl =
  32. CType(DataGridView.EditingControl, SearchEditingControl)
  33.  
  34. ' Use the default row value when Value property is null.
  35. If (Me.Value Is Nothing) Then
  36. ctl.Text = CStr(Me.DefaultNewRowValue).Assert
  37. Else
  38. ctl.Text = CStr(Me.Value).Assert
  39. End If
  40. End Sub
  41. End Class
  42.  
  43. Class SearchEditingControl
  44. Inherits PessBox
  45. Implements IDataGridViewEditingControl
  46.  
  47. Private dataGridViewControl As DataGridView
  48. Private valueIsChanged As Boolean = False
  49. Private rowIndexNum As Integer
  50.  
  51. Public Property EditingControlDataGridView As DataGridView Implements IDataGridViewEditingControl.EditingControlDataGridView
  52. Get
  53. Return dataGridViewControl
  54. End Get
  55. Set(value As DataGridView)
  56. dataGridViewControl = value
  57. End Set
  58. End Property
  59.  
  60. Public Property EditingControlFormattedValue As Object Implements IDataGridViewEditingControl.EditingControlFormattedValue
  61. Get
  62. Return Me.Text.Assert
  63. End Get
  64. Set(value As Object)
  65. Me.Text = CStr(value).Assert
  66. End Set
  67. End Property
  68.  
  69. Public Property EditingControlRowIndex As Integer Implements IDataGridViewEditingControl.EditingControlRowIndex
  70. Get
  71. Return rowIndexNum
  72. End Get
  73. Set(ByVal value As Integer)
  74. rowIndexNum = value
  75. End Set
  76. End Property
  77.  
  78. Public Property EditingControlValueChanged As Boolean Implements IDataGridViewEditingControl.EditingControlValueChanged
  79. Get
  80. Return valueIsChanged
  81. End Get
  82. Set(value As Boolean)
  83. valueIsChanged = value
  84. End Set
  85. End Property
  86.  
  87. Public ReadOnly Property EditingPanelCursor As Cursor Implements IDataGridViewEditingControl.EditingPanelCursor
  88. Get
  89. Return MyBase.Cursor
  90. End Get
  91. End Property
  92.  
  93. Public ReadOnly Property RepositionEditingControlOnValueChange As Boolean Implements IDataGridViewEditingControl.RepositionEditingControlOnValueChange
  94. Get
  95. Return False
  96. End Get
  97. End Property
  98.  
  99. Public Sub ApplyCellStyleToEditingControl(dataGridViewCellStyle As DataGridViewCellStyle) Implements IDataGridViewEditingControl.ApplyCellStyleToEditingControl
  100. Me.Font = dataGridViewCellStyle.Font
  101. Me.ForeColor = dataGridViewCellStyle.ForeColor
  102. Me.BackColor = dataGridViewCellStyle.BackColor
  103. End Sub
  104.  
  105. Public Sub PrepareEditingControlForEdit(selectAll As Boolean) Implements IDataGridViewEditingControl.PrepareEditingControlForEdit
  106. ' No preparation needs to be done.
  107. End Sub
  108.  
  109. Public Function EditingControlWantsInputKey(keyData As Keys, dataGridViewWantsInputKey As Boolean) As Boolean Implements IDataGridViewEditingControl.EditingControlWantsInputKey
  110. Select Case keyData And Keys.KeyCode
  111. Case Keys.Left, Keys.Up, Keys.Down, Keys.Right, Keys.Home, Keys.End, Keys.PageDown, Keys.PageUp
  112. Return True
  113. Case Else
  114. Return Not dataGridViewWantsInputKey
  115. End Select
  116. End Function
  117.  
  118. Public Function GetEditingControlFormattedValue(context As DataGridViewDataErrorContexts) As Object Implements IDataGridViewEditingControl.GetEditingControlFormattedValue
  119. Return Me.Text.Assert
  120. End Function
  121.  
  122. Protected Overrides Sub OnTextChanged(e As EventArgs)
  123. valueIsChanged = True
  124. Me.EditingControlDataGridView.NotifyCurrentCellDirty(True)
  125. MyBase.OnTextChanged(e)
  126. End Sub
  127.  
  128. End Class

Any help you guys could give me, or directions for properly implementing this, will be deeply appreciated. Thanks!