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!