I'm trying to display custom comboxbox in event DataGridView1 EditingControlShowing with VB.NET
One more thing I want the column to not display the ComboBox Column but the TextBox Column. Is it possible to apply?
The result of my code does not appear the custom component when I edit in the DatagridView event.
Maybe the code I posted is still wrong
so for column type DataGridViewTextBoxColumn
in header textProduct Name cmb
in design name ProductNamecmb
I want to display custom combobox in EditingControlShowing
event datagridview.
Please Guide me
Thanks
Information
column type DataGridViewTextBoxColumn
in header text `Product Name cmb`
in design name `ProductNamecmb`
column type DataGridViewTextBoxColumn
in header text `Product Name txt`
in design name `ProductNametxt`
Code in form1
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim row() As String = {"1", "Product 1", "Product 1", "1000"}
DataGridView1.Rows.Add(row)
row = New String() {"2", "Product 2", "Product 2", "2000"}
DataGridView1.Rows.Add(row)
row = New String() {"3", "Product 3", "Product 3", "3000"}
DataGridView1.Rows.Add(row)
row = New String() {"4", "Product 4", "Product 4", "4000"}
DataGridView1.Rows.Add(row)
End Sub
Public Sub addItems(ByVal col As AutoCompleteStringCollection)
col.Add("Product 1")
col.Add("Product 2")
col.Add("Product 3")
col.Add("Product 4")
col.Add("Product 5")
col.Add("Product 6")
End Sub
Private Sub DataGridView1_EditingControlShowing(sender As Object, e As DataGridViewEditingControlShowingEventArgs) Handles DataGridView1.EditingControlShowing
Dim titleText As String = DataGridView1.Columns("ProductNametxt").HeaderText
If titleText.Equals("Product Name txt") Then
Dim autoText As TextBox = TryCast(e.Control, TextBox)
If autoText IsNot Nothing Then
autoText.AutoCompleteMode = AutoCompleteMode.Suggest
autoText.AutoCompleteSource = AutoCompleteSource.CustomSource
Dim DataCollection As New AutoCompleteStringCollection()
addItems(DataCollection)
autoText.AutoCompleteCustomSource = DataCollection
End If
End If
Dim titlecmb As String = DataGridView1.Columns("ProductNamecmb").HeaderText
If titlecmb.Equals("Product Name cmb") Then
Dim autoText As FlatComboBox = TryCast(e.Control, FlatComboBox)
If autoText IsNot Nothing Then
autoText.DropDownStyle = ComboBoxStyle.DropDown
autoText.AutoCompleteMode = AutoCompleteMode.Suggest
autoText.AutoCompleteSource = AutoCompleteSource.CustomSource
Dim DataCollection As New AutoCompleteStringCollection()
addItems(DataCollection)
autoText.AutoCompleteCustomSource = DataCollection
End If
End If
End Sub
Private Sub DataGridView1_DataError(sender As Object, e As DataGridViewDataErrorEventArgs) Handles DataGridView1.DataError
If e.Context = DataGridViewDataErrorContexts.Commit Then
End If
End Sub
End Class
Code in custom component
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Public Class FlatComboBox
Inherits ComboBox
Private _borderColor As Color = Color.Green
<DefaultValue(GetType(Color), "Green")>
Public Property BorderColor As Color
Get
Return _borderColor
End Get
Set(ByVal value As Color)
If _borderColor <> value Then
_borderColor = value
Invalidate()
End If
End Set
End Property
Private _buttonColor As Color = Color.LightGray
<DefaultValue(GetType(Color), "LightGray")>
Public Property ButtonColor As Color
Get
Return _buttonColor
End Get
Set(ByVal value As Color)
If _buttonColor <> value Then
_buttonColor = value
Invalidate()
End If
End Set
End Property
Protected Overrides Sub WndProc(ByRef m As Message)
If m.Msg = WM_PAINT AndAlso DropDownStyle <> ComboBoxStyle.Simple Then
Dim clientRect = ClientRectangle
Dim dropDownButtonWidth = SystemInformation.HorizontalScrollBarArrowWidth
Dim outerBorder = New Rectangle(clientRect.Location, New Size(clientRect.Width - 1, clientRect.Height - 1))
Dim innerBorder = New Rectangle(outerBorder.X + 1, outerBorder.Y + 1, outerBorder.Width - dropDownButtonWidth - 2, outerBorder.Height - 2)
Dim innerInnerBorder = New Rectangle(innerBorder.X + 1, innerBorder.Y + 1, innerBorder.Width - 2, innerBorder.Height - 2)
Dim dropDownRect = New Rectangle(innerBorder.Right + 1, innerBorder.Y, dropDownButtonWidth, innerBorder.Height + 1)
If RightToLeft = RightToLeft.Yes Then
innerBorder.X = clientRect.Width - innerBorder.Right
innerInnerBorder.X = clientRect.Width - innerInnerBorder.Right
dropDownRect.X = clientRect.Width - dropDownRect.Right
dropDownRect.Width += 1
End If
Dim innerBorderColor = If(Enabled, BackColor, SystemColors.Control)
Dim outerBorderColor = If(Enabled, BorderColor, SystemColors.ControlDark)
Dim buttonColor As Color = If(Enabled, Me.ButtonColor, SystemColors.Control)
Dim middle = New Point(dropDownRect.Left + dropDownRect.Width \ 2, dropDownRect.Top + dropDownRect.Height \ 2)
Dim arrow = New Point() {
New Point(middle.X - 3, middle.Y - 2),
New Point(middle.X + 4, middle.Y - 2),
New Point(middle.X, middle.Y + 2)
}
Dim ps = New PAINTSTRUCT()
Dim shoulEndPaint As Boolean = False
Dim dc As IntPtr
If m.WParam = IntPtr.Zero Then
dc = BeginPaint(Handle, ps)
m.WParam = dc
shoulEndPaint = True
Else
dc = m.WParam
End If
Dim rgn = CreateRectRgn(innerInnerBorder.Left, innerInnerBorder.Top, innerInnerBorder.Right, innerInnerBorder.Bottom)
SelectClipRgn(dc, rgn)
DefWndProc(m)
DeleteObject(rgn)
rgn = CreateRectRgn(clientRect.Left, clientRect.Top, clientRect.Right, clientRect.Bottom)
SelectClipRgn(dc, rgn)
Using g = Graphics.FromHdc(dc)
Using b = New SolidBrush(buttonColor)
g.FillRectangle(b, dropDownRect)
End Using
Using b = New SolidBrush(outerBorderColor)
g.FillPolygon(b, arrow)
End Using
Using p = New Pen(innerBorderColor)
g.DrawRectangle(p, innerBorder)
g.DrawRectangle(p, innerInnerBorder)
End Using
Using p = New Pen(outerBorderColor)
g.DrawRectangle(p, outerBorder)
End Using
End Using
If shoulEndPaint Then
EndPaint(Handle, ps)
End If
DeleteObject(rgn)
Else
MyBase.WndProc(m)
End If
End Sub
Private Const WM_PAINT As Integer = &HF
<StructLayout(LayoutKind.Sequential)>
Public Structure RECT
Public L, T, R, B As Integer
End Structure
<StructLayout(LayoutKind.Sequential)>
Public Structure PAINTSTRUCT
Public hdc As IntPtr
Public fErase As Boolean
Public rcPaint_left As Integer
Public rcPaint_top As Integer
Public rcPaint_right As Integer
Public rcPaint_bottom As Integer
Public fRestore As Boolean
Public fIncUpdate As Boolean
Public reserved1 As Integer
Public reserved2 As Integer
Public reserved3 As Integer
Public reserved4 As Integer
Public reserved5 As Integer
Public reserved6 As Integer
Public reserved7 As Integer
Public reserved8 As Integer
End Structure
<DllImport("user32.dll")>
Private Shared Function BeginPaint(ByVal hWnd As IntPtr, <[In], [Out]> ByRef lpPaint As PAINTSTRUCT) As IntPtr
End Function
<DllImport("user32.dll")>
Private Shared Function EndPaint(ByVal hWnd As IntPtr, ByRef lpPaint As PAINTSTRUCT) As Boolean
End Function
<DllImport("gdi32.dll")>
Public Shared Function SelectClipRgn(ByVal hDC As IntPtr, ByVal hRgn As IntPtr) As Integer
End Function
<DllImport("user32.dll")>
Public Shared Function GetUpdateRgn(ByVal hwnd As IntPtr, ByVal hrgn As IntPtr, ByVal fErase As Boolean) As Integer
End Function
Public Enum RegionFlags
[ERROR] = 0
NULLREGION = 1
SIMPLEREGION = 2
COMPLEXREGION = 3
End Enum
<DllImport("gdi32.dll")>
Friend Shared Function DeleteObject(ByVal hObject As IntPtr) As Boolean
End Function
<DllImport("gdi32.dll")>
Private Shared Function CreateRectRgn(ByVal x1 As Integer, ByVal y1 As Integer, ByVal x2 As Integer, ByVal y2 As Integer) As IntPtr
End Function
End Class
desired result in datagridview event EditingControlShowing display like below :
Code recommendation update from @dr.null & update code OnTextChanged
in class FlatComboBox
TextboxCell
Public Class TextboxCell
Inherits DataGridViewTextBoxCell
Public Sub New()
' Use the text format.
Me.Style.Format = Nothing
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 FlatComboBox =
CType(DataGridView.EditingControl, FlatComboBox)
' Use the default row value when Value property is null.
If (Me.Value Is Nothing) Then
ctl.Text = CType(Me.DefaultNewRowValue, String)
Else
ctl.Text = CType(Me.Value, String)
End If
End Sub
Public Overrides ReadOnly Property EditType() As Type
Get
' Return the type of the editing control that TextboxCell uses.
Return GetType(FlatComboBox)
End Get
End Property
Public Overrides ReadOnly Property ValueType() As Type
Get
' Return the type of the value that TextboxCell contains.
Return GetType(String)
End Get
End Property
Public Overrides ReadOnly Property DefaultNewRowValue() As Object
Get
' Use the current string as the default value.
Return Nothing
End Get
End Property
End Class
TextboxColumn
Public Class TextboxColumn
Inherits DataGridViewColumn
Public Sub New()
MyBase.New(New TextboxCell())
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 TextboxCell.
If (value IsNot Nothing) AndAlso
Not value.GetType().IsAssignableFrom(GetType(TextboxCell)) _
Then
Throw New InvalidCastException("Must be a String")
End If
MyBase.CellTemplate = value
End Set
End Property
End Class
FlatComboBox
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Public Class FlatComboBox
Inherits ComboBox
Implements IDataGridViewEditingControl
Private dataGridViewControl As DataGridView
Private valueIsChanged As Boolean = False
Private rowIndexNum As Integer
Private _borderColor As Color = Color.Green
<DefaultValue(GetType(Color), "Green")>
Public Property BorderColor As Color
Get
Return _borderColor
End Get
Set(ByVal value As Color)
If _borderColor <> value Then
_borderColor = value
Invalidate()
End If
End Set
End Property
Private _buttonColor As Color = Color.LightGray
<DefaultValue(GetType(Color), "LightGray")>
Public Property ButtonColor As Color
Get
Return _buttonColor
End Get
Set(ByVal value As Color)
If _buttonColor <> value Then
_buttonColor = value
Invalidate()
End If
End Set
End Property
Public Property EditingControlFormattedValue As Object Implements IDataGridViewEditingControl.EditingControlFormattedValue
Get
Return Me.Text.ToString()
End Get
Set(ByVal value As Object)
Try
' This will throw an exception of the string is
' null, empty, or not in the format of a text.
Me.Text = CStr(value)
Catch
' In the case of an exception, just use the default
' value so we're not left with a null value.
Me.Text = Nothing
End Try
End Set
End Property
Public Function GetEditingControlFormattedValue(context As DataGridViewDataErrorContexts) As Object Implements IDataGridViewEditingControl.GetEditingControlFormattedValue
Return Me.Text.ToString()
End Function
Public Sub ApplyCellStyleToEditingControl(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.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 Sub PrepareEditingControlForEdit(selectAll As Boolean) Implements IDataGridViewEditingControl.PrepareEditingControlForEdit
' No preparation needs to be done.
End Sub
Public Property EditingControlValueChanged As Boolean Implements IDataGridViewEditingControl.EditingControlValueChanged
Get
Return valueIsChanged
End Get
Set(ByVal value As Boolean)
valueIsChanged = value
End Set
End Property
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 ReadOnly Property EditingPanelCursor As Cursor Implements IDataGridViewEditingControl.EditingPanelCursor
Get
Return MyBase.Cursor
End Get
End Property
Protected Overrides Sub OnSelectedIndexChanged(ByVal eventargs As EventArgs)
' Notify the DataGridView that the contents of the cell have changed.
EditingControlValueChanged = True
Me.EditingControlDataGridView.NotifyCurrentCellDirty(True)
MyBase.OnSelectedIndexChanged(eventargs)
End Sub
'update code
Protected Overrides Sub OnTextChanged(ByVal eventargs As EventArgs)
' Notify the DataGridView that the contents of the cell
' have changed.
Me.valueIsChanged = True
Me.EditingControlDataGridView.NotifyCurrentCellDirty(True)
MyBase.OnTextChanged(eventargs)
End Sub
Protected Overrides Sub WndProc(ByRef m As Message)
If m.Msg = WM_PAINT AndAlso DropDownStyle <> ComboBoxStyle.Simple Then
Dim clientRect = ClientRectangle
Dim dropDownButtonWidth = SystemInformation.HorizontalScrollBarArrowWidth
Dim outerBorder = New Rectangle(clientRect.Location, New Size(clientRect.Width - 1, clientRect.Height - 1))
Dim innerBorder = New Rectangle(outerBorder.X + 1, outerBorder.Y + 1, outerBorder.Width - dropDownButtonWidth - 2, outerBorder.Height - 2)
Dim innerInnerBorder = New Rectangle(innerBorder.X + 1, innerBorder.Y + 1, innerBorder.Width - 2, innerBorder.Height - 2)
Dim dropDownRect = New Rectangle(innerBorder.Right + 1, innerBorder.Y, dropDownButtonWidth, innerBorder.Height + 1)
If RightToLeft = RightToLeft.Yes Then
innerBorder.X = clientRect.Width - innerBorder.Right
innerInnerBorder.X = clientRect.Width - innerInnerBorder.Right
dropDownRect.X = clientRect.Width - dropDownRect.Right
dropDownRect.Width += 1
End If
Dim innerBorderColor = If(Enabled, BackColor, SystemColors.Control)
Dim outerBorderColor = If(Enabled, BorderColor, SystemColors.ControlDark)
Dim buttonColor As Color = If(Enabled, Me.ButtonColor, SystemColors.Control)
Dim middle = New Point(dropDownRect.Left + dropDownRect.Width \ 2, dropDownRect.Top + dropDownRect.Height \ 2)
Dim arrow = New Point() {
New Point(middle.X - 3, middle.Y - 2),
New Point(middle.X + 4, middle.Y - 2),
New Point(middle.X, middle.Y + 2)
}
Dim ps = New PAINTSTRUCT()
Dim shoulEndPaint As Boolean = False
Dim dc As IntPtr
If m.WParam = IntPtr.Zero Then
dc = BeginPaint(Handle, ps)
m.WParam = dc
shoulEndPaint = True
Else
dc = m.WParam
End If
Dim rgn = CreateRectRgn(innerInnerBorder.Left, innerInnerBorder.Top, innerInnerBorder.Right, innerInnerBorder.Bottom)
SelectClipRgn(dc, rgn)
DefWndProc(m)
DeleteObject(rgn)
rgn = CreateRectRgn(clientRect.Left, clientRect.Top, clientRect.Right, clientRect.Bottom)
SelectClipRgn(dc, rgn)
Using g = Graphics.FromHdc(dc)
Using b = New SolidBrush(buttonColor)
g.FillRectangle(b, dropDownRect)
End Using
Using b = New SolidBrush(outerBorderColor)
g.FillPolygon(b, arrow)
End Using
Using p = New Pen(innerBorderColor)
g.DrawRectangle(p, innerBorder)
g.DrawRectangle(p, innerInnerBorder)
End Using
Using p = New Pen(outerBorderColor)
g.DrawRectangle(p, outerBorder)
End Using
End Using
If shoulEndPaint Then
EndPaint(Handle, ps)
End If
DeleteObject(rgn)
Else
MyBase.WndProc(m)
End If
End Sub
Private Const WM_PAINT As Integer = &HF
<StructLayout(LayoutKind.Sequential)>
Public Structure RECT
Public L, T, R, B As Integer
End Structure
<StructLayout(LayoutKind.Sequential)>
Public Structure PAINTSTRUCT
Public hdc As IntPtr
Public fErase As Boolean
Public rcPaint_left As Integer
Public rcPaint_top As Integer
Public rcPaint_right As Integer
Public rcPaint_bottom As Integer
Public fRestore As Boolean
Public fIncUpdate As Boolean
Public reserved1 As Integer
Public reserved2 As Integer
Public reserved3 As Integer
Public reserved4 As Integer
Public reserved5 As Integer
Public reserved6 As Integer
Public reserved7 As Integer
Public reserved8 As Integer
End Structure
<DllImport("user32.dll")>
Private Shared Function BeginPaint(ByVal hWnd As IntPtr, <[In], [Out]> ByRef lpPaint As PAINTSTRUCT) As IntPtr
End Function
<DllImport("user32.dll")>
Private Shared Function EndPaint(ByVal hWnd As IntPtr, ByRef lpPaint As PAINTSTRUCT) As Boolean
End Function
<DllImport("gdi32.dll")>
Public Shared Function SelectClipRgn(ByVal hDC As IntPtr, ByVal hRgn As IntPtr) As Integer
End Function
<DllImport("user32.dll")>
Public Shared Function GetUpdateRgn(ByVal hwnd As IntPtr, ByVal hrgn As IntPtr, ByVal fErase As Boolean) As Integer
End Function
Public Enum RegionFlags
[ERROR] = 0
NULLREGION = 1
SIMPLEREGION = 2
COMPLEXREGION = 3
End Enum
<DllImport("gdi32.dll")>
Friend Shared Function DeleteObject(ByVal hObject As IntPtr) As Boolean
End Function
<DllImport("gdi32.dll")>
Private Shared Function CreateRectRgn(ByVal x1 As Integer, ByVal y1 As Integer, ByVal x2 As Integer, ByVal y2 As Integer) As IntPtr
End Function
End Class
result code in gif after update code from @dr.null & update code OnTextChanged
in class FlatComboBox