重写ComboBox类
Imports
System.Windows.Forms


Public
Class AutoCompleteComboBox
Class AutoCompleteComboBox
Inherits ComboBox

Public Sub New()Sub New()
MyBase.New()
End Sub

Private mResetOnClear As Boolean = False

Protected Overrides Sub RefreshItem()Sub RefreshItem(ByVal index As Integer)
MyBase.RefreshItem(index)
End Sub


Protected Overrides Sub SetItemsCore()Sub SetItemsCore(ByVal items As System.Collections.IList)
MyBase.SetItemsCore(items)
End Sub


Public Shadows Sub KeyPress()Sub KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles MyBase.KeyPress
Dim intIndex As Integer
Dim strEntry As String

If Char.IsControl(e.KeyChar) Then
If MyBase.SelectionStart <= 1 Then
If mResetOnClear Then
MyBase.SelectedIndex = 0
MyBase.SelectAll()
Else
MyBase.Text = String.Empty
MyBase.SelectedIndex = -1
End If
e.Handled = True
Exit Sub
End If
If MyBase.SelectionLength = 0 Then
strEntry = MyBase.Text.Substring(0, MyBase.Text.Length - 1)
Else
strEntry = MyBase.Text.Substring(0, MyBase.SelectionStart - 1)
End If
ElseIf (Not Char.IsLetterOrDigit(e.KeyChar)) And (Not Char.IsWhiteSpace(e.KeyChar)) Then '< 32 Or KeyAscii > 127 Then
Exit Sub
Else
If MyBase.SelectionLength = 0 Then
strEntry = UCase(MyBase.Text & e.KeyChar)
Else
strEntry = MyBase.Text.Substring(0, MyBase.SelectionStart) & e.KeyChar
End If
End If

MyBase.DroppedDown = Char.IsLetterOrDigit(e.KeyChar)

intIndex = MyBase.FindString(strEntry)
If intIndex <> -1 Then
MyBase.SelectedIndex = intIndex
MyBase.SelectionStart = strEntry.Length
MyBase.SelectionLength = MyBase.Text.Length - MyBase.SelectionStart
End If

e.Handled = True
Exit Sub
End Sub


Public Property ResetOnClear()Property ResetOnClear() As Boolean
Get
Return mResetOnClear
End Get
Set(ByVal Value As Boolean)
mResetOnClear = Value
End Set
End Property
End Class
实现类
Option
Strict
On
Option
Explicit
On
Imports
System.Collections
Imports
System.ComponentModel
Imports
System.Drawing
Imports
System.Windows.Forms
Imports
System.Data


Public
Class DataGridComboBox
Class DataGridComboBox
Inherits AutoCompleteComboBox

Public Sub New()Sub New()
MyBase.New()
End Sub
Public isInEditOrNavigateMode As Boolean = True

End Class


Public
Class DataGridComboBoxColumnStyle
Class DataGridComboBoxColumnStyle
Inherits DataGridColumnStyle

Private xMargin As Integer = 2
Private yMargin As Integer = 1
Private Combo As DataGridComboBox
Private _DisplayMember As String
Private _ValueMember As String

Private OldVal As String = String.Empty
Private InEdit As Boolean = False


Public Sub New()Sub New(ByRef DataSource As DataTable, _
ByVal DisplayMember As Integer, _
ByVal ValueMember As Integer)

Combo = New DataGridComboBox
_DisplayMember = DataSource.Columns.Item(index:=DisplayMember).ToString
_ValueMember = DataSource.Columns.Item(index:=ValueMember).ToString

With Combo
.Visible = False
.DataSource = DataSource
.DisplayMember = _DisplayMember
.ValueMember = _ValueMember
End With
End Sub


Public Sub New()Sub New(ByRef DataSource As DataTable, _
ByVal DisplayMember As String, _
ByVal ValueMember As String)

Combo = New DataGridComboBox
With Combo
.Visible = False
.DataSource = DataSource
.DisplayMember = DisplayMember
.ValueMember = ValueMember
End With

End Sub


Protected Overloads Overrides Sub Abort()Sub Abort(ByVal RowNum As Integer)
Debug.WriteLine("Abort()")
RollBack()
HideComboBox()
EndEdit()
End Sub


Protected Overloads Overrides Function Commit()Function Commit(ByVal DataSource As CurrencyManager, _
ByVal RowNum As Integer) As Boolean
HideComboBox()
If Not InEdit Then
Return True
End If

Try
Dim Value As Object = Combo.SelectedValue
If NullText.Equals(Value) Then
Value = Convert.DBNull
End If
SetColumnValueAtRow(DataSource, RowNum, Value)
Catch e As Exception
RollBack()
Return False
End Try
EndEdit()
Return True
End Function


Protected Overloads Overrides Sub ConcedeFocus()Sub ConcedeFocus()
Combo.Visible = False
End Sub


Protected Overloads Overrides Sub Edit()Sub Edit(ByVal Source As CurrencyManager, _
ByVal Rownum As Integer, _
ByVal Bounds As Rectangle, _
ByVal [ReadOnly] As Boolean, _
ByVal InstantText As String, _
ByVal CellIsVisible As Boolean)

Combo.Text = String.Empty

Dim OriginalBounds As Rectangle = Bounds

OldVal = Combo.Text

If CellIsVisible Then
Bounds.Offset(xMargin, yMargin)
Bounds.Width -= xMargin * 2
Bounds.Height -= yMargin
Combo.Bounds = Bounds
Combo.Visible = True
Else
Combo.Bounds = OriginalBounds
Combo.Visible = False
End If

Combo.SelectedValue = GetText(GetColumnValueAtRow(Source, Rownum))

If Not InstantText Is Nothing Then
Combo.SelectedValue = InstantText
End If

Combo.RightToLeft = Me.DataGridTableStyle.DataGrid.RightToLeft
Combo.Focus()

If InstantText Is Nothing Then
Combo.SelectAll()
Else
Dim [End] As Integer = Combo.Text.Length
Combo.Select([End], 0)
End If

If Combo.Visible Then
DataGridTableStyle.DataGrid.Invalidate(OriginalBounds)
End If

InEdit = True

End Sub


Protected Overloads Overrides Function GetMinimumHeight()Function GetMinimumHeight() As Integer
Return Combo.PreferredHeight + yMargin
End Function


Protected Overloads Overrides Function GetPreferredHeight()Function GetPreferredHeight(ByVal g As Graphics, _
ByVal Value As Object) As Integer
Debug.WriteLine("GetPreferredHeight()")
Dim NewLineIndex As Integer = 0
Dim NewLines As Integer = 0
Dim ValueString As String = Me.GetText(Value)
Do
While NewLineIndex <> -1
NewLineIndex = ValueString.IndexOf("r\n", NewLineIndex + 1)
NewLines += 1
End While
Loop

Return FontHeight * NewLines + yMargin
End Function


Protected Overloads Overrides Function GetPreferredSize()Function GetPreferredSize(ByVal g As Graphics, _
ByVal Value As Object) As Size
Dim Extents As Size = Size.Ceiling(g.MeasureString(GetText(Value), _
Me.DataGridTableStyle.DataGrid.Font))
Extents.Width += xMargin * 2 + DataGridTableGridLineWidth
Extents.Height += yMargin
Return Extents
End Function


Protected Overloads Overrides Sub Paint()Sub Paint(ByVal g As Graphics, _
ByVal Bounds As Rectangle, _
ByVal Source As CurrencyManager, _
ByVal RowNum As Integer)
Paint(g, Bounds, Source, RowNum, False)
End Sub


Protected Overloads Overrides Sub Paint()Sub Paint(ByVal g As Graphics, _
ByVal Bounds As Rectangle, _
ByVal Source As CurrencyManager, _
ByVal RowNum As Integer, _
ByVal AlignToRight As Boolean)
Dim Text As String = GetText(GetColumnValueAtRow(Source, RowNum))
PaintText(g, Bounds, Text, AlignToRight)
End Sub


Protected Overloads Sub Paint()Sub Paint(ByVal g As Graphics, _
ByVal Bounds As Rectangle, _
ByVal Source As CurrencyManager, _
ByVal RowNum As Integer, _
ByVal BackBrush As Brush, _
ByVal ForeBrush As Brush, _
ByVal AlignToRight As Boolean)

Dim Text As String = GetText(GetColumnValueAtRow(Source, RowNum))
PaintText(g, Bounds, Text, BackBrush, ForeBrush, AlignToRight)
End Sub


Protected Overloads Overrides Sub SetDataGridInColumn()Sub SetDataGridInColumn(ByVal Value As DataGrid)
MyBase.SetDataGridInColumn(Value)
If Not (Combo.Parent Is Value) Then
If Not (Combo.Parent Is Nothing) Then
Combo.Parent.Controls.Remove(Combo)
End If
End If

If Not (Value Is Nothing) Then Value.Controls.Add(Combo)
End Sub


Protected Overloads Overrides Sub UpdateUI()Sub UpdateUI(ByVal Source As CurrencyManager, _
ByVal RowNum As Integer, ByVal InstantText As String)
Combo.Text = GetText(GetColumnValueAtRow(Source, RowNum))
If Not (InstantText Is Nothing) Then
Combo.Text = InstantText
End If
End Sub


Private ReadOnly Property DataGridTableGridLineWidth()Property DataGridTableGridLineWidth() As Integer
Get
If Me.DataGridTableStyle.GridLineStyle = DataGridLineStyle.Solid Then
Return 1
Else
Return 0
End If
End Get
End Property


Private Sub EndEdit()Sub EndEdit()
InEdit = False
Invalidate()
End Sub


Private Function GetText()Function GetText(ByVal Value As Object) As String
If Value Is System.DBNull.Value Then Return NullText

If Not Value Is Nothing Then
Return Value.ToString
Else
Return String.Empty
End If

End Function


Private Sub HideComboBox()Sub HideComboBox()
If Combo.Focused Then
Me.DataGridTableStyle.DataGrid.Focus()
End If
Combo.Visible = False
End Sub


Private Sub RollBack()Sub RollBack()
Combo.Text = OldVal
End Sub


Private Sub PaintText()Sub PaintText(ByVal g As Graphics, _
ByVal Bounds As Rectangle, _
ByVal Text As String, _
ByVal AlignToRight As Boolean)

Dim BackBrush As Brush = New SolidBrush(Me.DataGridTableStyle.BackColor)
Dim ForeBrush As Brush = New SolidBrush(Me.DataGridTableStyle.ForeColor)
PaintText(g, Bounds, Text, BackBrush, ForeBrush, AlignToRight)
End Sub


Private Sub PaintText()Sub PaintText(ByVal g As Graphics, _
ByVal TextBounds As Rectangle, _
ByVal Text As String, _
ByVal BackBrush As Brush, _
ByVal ForeBrush As Brush, _
ByVal AlignToRight As Boolean)

Dim Rect As Rectangle = TextBounds
Dim RectF As RectangleF = RectF.op_Implicit(Rect) ' Convert to RectangleF
Dim Format As StringFormat = New StringFormat

If AlignToRight Then
Format.FormatFlags = StringFormatFlags.DirectionRightToLeft
End If

Select Case Me.Alignment
Case Is = HorizontalAlignment.Left
Format.Alignment = StringAlignment.Near
Case Is = HorizontalAlignment.Right
Format.Alignment = StringAlignment.Far
Case Is = HorizontalAlignment.Center
Format.Alignment = StringAlignment.Center
End Select

Format.FormatFlags = Format.FormatFlags Or StringFormatFlags.NoWrap
g.FillRectangle(Brush:=BackBrush, Rect:=Rect)

Rect.Offset(0, yMargin)
Rect.Height -= yMargin
g.DrawString(Text, Me.DataGridTableStyle.DataGrid.Font, ForeBrush, RectF, Format)
Format.Dispose()

End Sub


Public ReadOnly Property ComboBox()Property ComboBox() As ComboBox
Get
Return Combo
End Get
End Property
End Class
测试代码
Private
Sub Form_Load()
Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
InitForm(DataGrid1)
Dim namesDataTable As DataTable
namesDataTable = New DataTable("NamesTable")

namesDataTable.Columns.Add("Name", GetType(String))
namesDataTable.Columns.Add("Sex", GetType(String))

Dim namesDataSet As DataSet = New DataSet
namesDataSet.Tables.Add(namesDataTable)
DataGrid1.DataSource = namesDataSet
DataGrid1.DataMember = "NamesTable"

AddGridStyle(DataGrid1)
AddData(namesDataTable)

End Sub


Private
Sub AddGridStyle()
Sub AddGridStyle(ByRef myGrid As DataGrid)
Dim myGridStyle As DataGridTableStyle = New DataGridTableStyle
myGridStyle.MappingName = "NamesTable"

Dim nameColumnStyle As DataGridTextBoxColumn = New DataGridTextBoxColumn
nameColumnStyle.MappingName = "Name"
nameColumnStyle.HeaderText = "Name"
myGridStyle.GridColumnStyles.Add(nameColumnStyle)

Dim mydt As DataTable
mydt = New DataTable
mydt.Columns.Add("id", GetType(String))
mydt.Columns.Add("text", GetType(String))

Dim newRowW As DataRow
newRowW = mydt.NewRow()
newRowW(0) = "0"
newRowW(1) = "女"
Dim newRowM As DataRow
newRowM = mydt.NewRow()
newRowM(0) = "1"
newRowM(1) = "男"
mydt.Rows.Add(newRowM)
mydt.Rows.Add(newRowW)

Dim comboxColumnStyle As New DataGridComboBoxColumnStyle(mydt, 1, 1)
comboxColumnStyle.MappingName = "Sex"
comboxColumnStyle.HeaderText = "Sex"
comboxColumnStyle.Width = 100
myGridStyle.GridColumnStyles.Add(comboxColumnStyle)

myGrid.TableStyles.Add(myGridStyle)
End Sub


Private
Sub AddData()
Sub AddData(ByRef namesDataTable As DataTable)
Dim dRow As DataRow = namesDataTable.NewRow()
dRow("Name") = "小站"
dRow("Sex") = "女"
namesDataTable.Rows.Add(dRow)

dRow = namesDataTable.NewRow()
dRow("Name") = "小李"
dRow("Sex") = "男"
namesDataTable.Rows.Add(dRow)

dRow = namesDataTable.NewRow()
dRow("Name") = "小吴"
dRow("Sex") = "女"
namesDataTable.Rows.Add(dRow)

namesDataTable.AcceptChanges()
End Sub


Private
Sub InitForm()
Sub InitForm(ByRef myGrid As DataGrid)
myGrid.TabStop = True
myGrid.TabIndex = 1
End Sub
转载于:https://www.cnblogs.com/timsoft/articles/414084.html