running32
asked on
Add button to unbound row in datagrid
I can add to a column to my Datagrid titled Survey but how can I add a button to this column? Thank you for your help
myDataSet.Tables(0).Column s.Add("Sur vey", Type.GetType("System.Boole an"), False)
Dim dr As DataRow
For Each dr In myDataSet.Tables(0).Rows
Next
myDataSet.Tables(0).Column
Dim dr As DataRow
For Each dr In myDataSet.Tables(0).Rows
Next
ASKER
I tried this, but I want to put a combo box and button in a datagrid.
Thanks
Thanks
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ComboBox w/ AutoComplete
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
Inherits ComboBox
Public Sub New()
MyBase.New()
End Sub
Public isInEditOrNavigateMode As Boolean = True
Private setIndex As Int32
Private processCLOSEUP As Boolean = True
Private bForceFound As Boolean = False
Public Event ChangeIndex(ByVal sender As Object, ByVal e As System.EventArgs)
Const WM_KEYUP As Int32 = &H101
Const WM_KEYDOWN As Int32 = &H100
Const CBN_DROPDOWN As Int32 = &H7
Const CBN_CLOSEUP As Int32 = &H8
Const CBN_SELENDOK As Int32 = &H9
Const CBN_SELCHANGE As Int32 = &H1
Const WM_COMMAND As Int32 = &H111
Const WM_USER As Int32 = &H400
Const OCM__BASE As Int32 = WM_USER + &H1C00
Const OCM_COMMAND As Int32 = OCM__BASE + WM_COMMAND
Sub New(ByVal bForceFound As Boolean)
Me.bForceFound = bForceFound
End Sub
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Messa ge)
Select Case m.Msg
Case OCM_COMMAND
Dim mIntPtr As Int32 = m.WParam.ToInt32
'Get notification of combobox list dropdown
'and enable setting index on list
'closeup
If (mIntPtr >> 16) = CBN_DROPDOWN Then
processCLOSEUP = True
End If
'If user selects an item in the list portion while dropped down
'disable setting index on closeup
If (mIntPtr >> 16) = CBN_SELENDOK Then
processCLOSEUP = False
End If
'If list portion is closing and user
'has not made a specific selection in
'the list area, set index
If processCLOSEUP Then
If (mIntPtr >> 16) = CBN_CLOSEUP Then
If Me.Items.Count > 0 Then
Me.SelectedIndex = setIndex
End If
End If
End If
End Select
MyBase.WndProc(m)
End Sub
Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Messa ge, ByVal keyData As System.Windows.Forms.Keys) As Boolean
Select Case msg.WParam.ToInt32()
Case CInt(Keys.Up)
If MyBase.Items.Count > 0 And MyBase.SelectedIndex > 0 Then
If MyBase.DroppedDown = False Then
MyBase.DroppedDown = True
End If
MyBase.SelectedIndex -= 1
setIndex = MyBase.SelectedIndex
End If
Return True
Case CInt(Keys.Down)
If MyBase.Items.Count > 0 And MyBase.SelectedIndex < MyBase.Items.Count - 1 Then
If MyBase.DroppedDown = False Then
MyBase.DroppedDown = True
processCLOSEUP = True
End If
MyBase.SelectedIndex += 1
setIndex = MyBase.SelectedIndex
End If
Return True
Case CInt(Keys.Right)
Return True
Case CInt(Keys.Left)
Return False
End Select
Return MyBase.ProcessCmdKey(msg, keyData)
End Function 'ProcessCmdKey
Protected Overrides Function ProcessKeymessage(ByRef m As System.Windows.Forms.Messa ge) As Boolean
'Handles the tab key skipping over columns
If m.Msg = WM_KEYUP Then
If m.WParam.ToInt32 = CInt(Keys.Tab) Then
Return True
ElseIf m.WParam.ToInt32 = CInt(Keys.Up) Or m.WParam.ToInt32 = CInt(Keys.Down) Then
'Combo_KeyDown(New Object, New KeyEventArgs(CType(m.WPara m.ToInt32, Keys)))
Return True
Else
Return MyBase.ProcessKeyMessage(m )
End If
Else
Return MyBase.ProcessKeyMessage(m )
End If
End Function
Private Sub Combo_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEv entArgs) Handles MyBase.KeyUp
' Do nothing for certain keys such as navigation keys
With e
If ((e.KeyCode = Keys.Back) Or _
(.KeyCode = Keys.Enter) Or _
(.KeyCode = Keys.Left) Or _
(.KeyCode = Keys.Right) Or _
(.KeyCode = Keys.Up) Or _
(.KeyCode = Keys.Delete) Or _
(.KeyCode = Keys.Down) Or _
(.KeyCode = Keys.PageUp) Or _
(.KeyCode = Keys.PageDown) Or _
(.KeyCode = Keys.Home) Or _
(.KeyCode = Keys.ShiftKey) Or _
(.KeyCode = Keys.End) Or _
(.KeyCode = Keys.Tab AndAlso .KeyCode = Keys.Shift)) Then
Return
End If
End With
' Store the actual text that has been typed
Dim TypedText As String = Text
Dim index As Integer = FindString(TypedText)
' Get the text of the first match
If index > -1 Then
Dim foundText As String = Me.GetItemText(Items(index ))
Dim sAppendText As String = foundText.Substring(TypedT ext.Length )
Text = TypedText & sAppendText
' Select the portion of the text that was automatically
' added so further typing will replace it
SelectionStart = TypedText.Length
SelectionLength = sAppendText.Length
SelectedIndex = index
'For setting the the index using
'CBN_CLOSEUP notification (no user selection
'in dropped down list portion
If processCLOSEUP Then
Me.setIndex = index
End If
Else
'Enforces not in list
If bForceFound = True Then
ResetText()
End If
End If
End Sub
Private Sub Combo_SelectionChangeCommi tted(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.SelectionChangeComm itted
RaiseEvent ChangeIndex(sender, e)
End Sub
'Private Sub Combo_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEv entArgs) Handles MyBase.KeyDown
' If Me.Items.Count > 0 Then
' Select Case e.KeyCode
' Case Keys.Down
' If Me.SelectedIndex < Me.Items.Count - 1 Then
' Me.SelectedIndex += 1
' Else
' Me.SelectedIndex = 0
' End If
' Case Keys.Up
' If Me.SelectedIndex > 0 Then
' Me.SelectedIndex -= 1
' Else
' Me.SelectedIndex = Me.Items.Count - 1
' End If
' End Select
' End If
'End Sub
End Class
Public Class DataGridComboBoxColumnStyl e
Inherits DataGridColumnStyle
'
' UI constants
'
Private xMargin As Integer = 2
Private yMargin As Integer = 0
'
'
Public WithEvents Combo As DataGridComboBox
Private m_DisplayMember, m_ValueMember As String
Private WithEvents cm As CurrencyManager
Private dV As New DataView
Private mDropDown As Boolean
'
' Used to track editing state
'
Private OldVal As String = String.Empty
Private InEdit As Boolean = False
Private bForceFound As Boolean
Private bAllowNew As Boolean
Public Event CreateNew(ByVal strText As String)
Public Event SelectedValue_Changed(ByVa l sender As Object, ByVal e As EventArgs)
Public Event Leave()
#Region " New "
Public Sub New()
End Sub
' DATATABLE
' Create a new column - DisplayMember, ValueMember
' Passed by ordinal
'
Public Sub New(ByVal DataSource As DataTable, ByVal DisplayMember As Integer, ByVal ValueMember As Integer, ByVal _DropDownWidth As Integer, Optional ByVal bAllowNew As Boolean = True, Optional ByVal DropDownOnEdit As Boolean = True, Optional ByVal ForceFind As Boolean = False)
Me.bForceFound = ForceFind
Me.Combo = New DataGridComboBox(bForceFou nd)
Me.bAllowNew = bAllowNew
InEdit = False
Me.m_DisplayMember = DataSource.Columns.Item(in dex:=Displ ayMember). ToString
Me.m_ValueMember = DataSource.Columns.Item(in dex:=Value Member).To String
With Me.Combo
.Visible = False
.DataSource = DataSource
.DisplayMember = m_DisplayMember
.ValueMember = m_ValueMember
.DropDownStyle = ComboBoxStyle.DropDown
.DropDownWidth = _DropDownWidth
.MaxDropDownItems = 20
mDropDown = DropDownOnEdit
AddHandler .Enter, AddressOf Me.DataGridComboBox_Enter
AddHandler .Leave, AddressOf DataGridComboBox_Leave
AddHandler .KeyPress, AddressOf DataGridComboBox_KeyPress
End With
Me.dV = DataSource.DefaultView
End Sub
' DATATABLE
' Create a new column - DisplayMember, ValueMember
' passed by string
'
Public Sub New(ByVal DataSource As DataTable, ByVal DisplayMember As String, ByVal ValueMember As String, ByVal _DropDownWidth As Integer, Optional ByVal bAllowNew As Boolean = True, Optional ByVal DropDownOnEdit As Boolean = True, Optional ByVal ForceFind As Boolean = False)
Me.bForceFound = ForceFind
Me.Combo = New DataGridComboBox(bForceFou nd)
Me.bAllowNew = bAllowNew
InEdit = False
With Me.Combo
.Visible = False
.DataSource = DataSource
.DisplayMember = DisplayMember
.ValueMember = ValueMember
.DropDownStyle = ComboBoxStyle.DropDown
.DropDownWidth = _DropDownWidth
.MaxDropDownItems = 20
mDropDown = DropDownOnEdit
AddHandler .Enter, AddressOf Me.DataGridComboBox_Enter
AddHandler .Leave, AddressOf DataGridComboBox_Leave
AddHandler .KeyPress, AddressOf DataGridComboBox_KeyPress
End With
Me.dV = DataSource.DefaultView
End Sub
' DATVIEW
' Create a new column - DisplayMember, ValueMember
' Passed by ordinal
'
Public Sub New(ByVal DataSource As DataView, ByVal DisplayMember As Integer, ByVal ValueMember As Integer, ByVal _DropDownWidth As Integer, Optional ByVal bAllowNew As Boolean = True, Optional ByVal DropDownOnEdit As Boolean = True, Optional ByVal ForceFind As Boolean = False)
Me.bForceFound = ForceFind
Me.Combo = New DataGridComboBox(bForceFou nd)
Me.bAllowNew = bAllowNew
InEdit = False
Me.m_DisplayMember = DataSource.Table.Columns.I tem(index: =DisplayMe mber).ToSt ring
Me.m_ValueMember = DataSource.Table.Columns.I tem(index: =ValueMemb er).ToStri ng
With Me.Combo
.Visible = False
.DataSource = DataSource
.DisplayMember = m_DisplayMember
.ValueMember = m_ValueMember
.DropDownStyle = ComboBoxStyle.DropDown
.DropDownWidth = _DropDownWidth
.MaxDropDownItems = 20
mDropDown = DropDownOnEdit
AddHandler .Enter, AddressOf Me.DataGridComboBox_Enter
AddHandler .Leave, AddressOf DataGridComboBox_Leave
AddHandler .KeyPress, AddressOf DataGridComboBox_KeyPress
End With
Me.dV = DataSource
End Sub
' DATAVIEW
' Create a new column - DisplayMember, ValueMember
' passed by string
'
Public Sub New(ByVal DataSource As DataView, ByVal DisplayMember As String, ByVal ValueMember As String, ByVal _DropDownWidth As Integer, Optional ByVal bAllowNew As Boolean = True, Optional ByVal DropDownOnEdit As Boolean = True, Optional ByVal ForceFind As Boolean = False)
Me.bForceFound = ForceFind
Me.Combo = New DataGridComboBox(bForceFou nd)
Me.bAllowNew = bAllowNew
InEdit = False
With Me.Combo
.Visible = False
.DataSource = DataSource
.DisplayMember = DisplayMember
.ValueMember = ValueMember
.DropDownStyle = ComboBoxStyle.DropDown
.DropDownWidth = _DropDownWidth
.MaxDropDownItems = 20
mDropDown = DropDownOnEdit
AddHandler .Enter, AddressOf Me.DataGridComboBox_Enter
AddHandler .Leave, AddressOf DataGridComboBox_Leave
AddHandler .KeyPress, AddressOf DataGridComboBox_KeyPress
End With
Me.dV = DataSource
End Sub
#End Region
'
'------------------------- ---------- ---------- ---------
' Methods overridden from DataGridColumnStyle
'------------------------- ---------- ---------- ---------
'
' Abort Changes
'
Protected Overloads Overrides Sub Abort(ByVal RowNum As Integer)
RollBack()
HideComboBox()
EndEdit()
End Sub
'
' Commit Changes
'
Protected Overloads Overrides Function Commit(ByVal DataSource As CurrencyManager, ByVal RowNum As Integer) As Boolean
If bForceFound = False And bAllowNew = True Then
Dim strFoundText As String = Me.Combo.Text
If Me.Combo.FindStringExact(s trFoundTex t) = -1 And strFoundText.Length > 0 Then
If MessageBox.Show("Cannot find Item: '" & strFoundText & "'" & vbCrLf & "Would you like to create a new Item ?", "Create New", MessageBoxButtons.YesNo, MessageBoxIcon.Question) = DialogResult.Yes Then
RaiseEvent CreateNew(strFoundText)
InEdit = True
End If
End If
End If
HideComboBox()
If Not InEdit Then
Return True
End If
InEdit = False
Try
Dim Value As Object = Me.Combo.SelectedValue
If NullText.Equals(Value) Then
Value = Convert.DBNull
End If
SetColumnValueAtRow(DataSo urce, RowNum, Me.Combo.SelectedValue)
Catch ex As Exception
Debug.WriteLine(ex.ToStrin g)
RollBack()
Return False
End Try
EndEdit()
Return True
End Function
'
' Try to Handle SelectionChangeCommitted.. .
'
Protected Sub SelectionChanged(ByVal sender As Object, ByVal e As EventArgs) Handles Combo.ChangeIndex
' If the parent of the datagrid is a form...
If TypeOf (MyBase.DataGridTableStyle .DataGrid. Parent) Is Form Then
' Get a reference to the form, to get the currencymanager.
Dim frm As Form = CType(MyBase.DataGridTable Style.Data Grid.Paren t, Form)
' Get the currency manager associated with the form.
Dim cm As CurrencyManager = CType(frm.BindingContext(M yBase.Data GridTableS tyle.DataG rid.DataSo urce, MyBase.DataGridTableStyle. DataGrid.D ataMember) , CurrencyManager)
' Try and set the value.
Try
SetColumnValueAtRow(cm, MyBase.DataGridTableStyle. DataGrid.C urrentRowI ndex, Me.Combo.SelectedValue)
Catch ex As Exception
Debug.WriteLine(ex.Message )
End Try
End If
End Sub
'
' Edit Grid
'
Protected Overloads Overrides 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)
Try
With Me.Combo
'.Text = String.Empty
Dim OriginalBounds As Rectangle = Bounds
OldVal = .Text
If CellIsVisible Then
Bounds.Offset(xMargin, yMargin)
Bounds.Width -= xMargin * 2
Bounds.Height -= yMargin
.Bounds = Bounds
.Visible = True
Else
.Bounds = OriginalBounds
.Visible = False
End If
If .FindStringExact(.Text) > -1 Then
.SelectedValue = GetColumnValueAtRow(Source , Rownum)
Else
.SelectedIndex = -1
End If
If Not InstantText Is Nothing Then
.SelectedValue = InstantText
Else
.Select(.Text.Length, 0)
End If
.RightToLeft = Me.DataGridTableStyle.Data Grid.Right ToLeft
.Focus()
If .Visible Then
Me.DataGridTableStyle.Data Grid.Inval idate(Orig inalBounds )
End If
End With
InEdit = True
Catch ex As Exception
Debug.WriteLine(ex.ToStrin g)
InEdit = False
RollBack()
End Try
End Sub
Protected Overloads Overrides Function GetMinimumHeight() As Integer
Return Me.Combo.PreferredHeight + yMargin
End Function
Protected Overloads Overrides Function GetPreferredHeight(ByVal g As Graphics, _
ByVal Value As Object) As Integer
Dim NewLineIndex As Integer = 0
Dim NewLines As Integer = 0
Dim ValueString As String = Me.GetTxt(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(ByVal g As Graphics, _
ByVal Value As Object) As Size
Dim Extents As Size = Size.Ceiling(g.MeasureStri ng(GetTxt( Value), _
Me.DataGridTableStyle.Data Grid.Font) )
Extents.Width += xMargin * 2 + DataGridTableGridLineWidth
Extents.Height += yMargin
Return Extents
End Function
Protected Overloads Overrides 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(ByVal g As Graphics, _
ByVal Bounds As Rectangle, _
ByVal Source As CurrencyManager, _
ByVal RowNum As Integer, _
ByVal AlignToRight As Boolean)
Dim Text As String = GetTxt(GetColumnValueAtRow (Source, RowNum))
PaintText(g, Bounds, Text, RowNum, AlignToRight)
End Sub
Protected Overloads 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 = GetTxt(GetColumnValueAtRow (Source, RowNum))
PaintText(g, Bounds, Text, BackBrush, ForeBrush, RowNum, AlignToRight)
End Sub
Protected Overloads Overrides Sub SetDataGridInColumn(ByVal Value As DataGrid)
MyBase.SetDataGridInColumn (Value)
If Not (Me.Combo.Parent Is Value) Then
If Not (Me.Combo.Parent Is Nothing) Then
Me.Combo.Parent.Controls.R emove(Me.C ombo)
End If
End If
If Not (Value Is Nothing) Then Value.Controls.Add(Me.Comb o)
End Sub
Protected Overloads Overrides Sub UpdateUI(ByVal Source As CurrencyManager, _
ByVal RowNum As Integer, ByVal InstantText As String)
If Not (InstantText Is Nothing) Then
Me.Combo.Text = InstantText
End If
End Sub
'------------------------- ---------- ---------- ---------- ---------- -----
' Helper Methods
'------------------------- ---------- ---------- ---------- ---------- -----
Private ReadOnly Property DataGridTableGridLineWidth () As Integer
Get
If DataGridTableStyle.GridLin eStyle = DataGridLineStyle.Solid Then
Return 1
Else
Return 0
End If
End Get
End Property
Public Sub SetDataSource(ByVal dt As DataTable)
Me.Combo.DataSource = dt
End Sub
Private Sub EndEdit()
InEdit = False
Invalidate()
End Sub
Private Function GetTxt(ByVal s As Object) As String
Try
If s Is DBNull.Value Then Return NullText
If Not s Is Nothing Then
'Set up the delimiters for the search string based on TypeOf s
Dim strFilter As String = String.Empty
If TypeOf (Me.Combo.ValueMember) Is String Then
strFilter = "'" & s.ToString & "'"
ElseIf TypeOf (Me.Combo.ValueMember) Is DateTime Then
strFilter = "#" & s.ToString & "#"
Else
strFilter = s.ToString
End If
'Use datatable.select method
Dim drarr() As DataRow = Me.dV.Table.Select(Me.Comb o.ValueMem ber & " = " & strFilter)
If drarr.Length > 0 Then 'Value found
'Return associated Display Member
Return drarr(0)(Me.Combo.DisplayM ember).ToS tring
Else 'Value NOT found
Return String.Empty
End If
Else
Return String.Empty
End If
Catch ex As Exception
Console.WriteLine(ex.ToStr ing)
End Try
End Function
Private Sub HideComboBox()
If Me.Combo.Focused Then
Me.DataGridTableStyle.Data Grid.Focus ()
End If
Me.Combo.Visible = False
End Sub
Private Sub RollBack()
Me.Combo.Text = OldVal
End Sub
Private Sub PaintText(ByVal g As Graphics, ByVal Bounds As Rectangle, ByVal Text As String, ByVal RowNum As Integer, _
ByVal AlignToRight As Boolean)
Dim BackBrush As Brush
Dim ForeBrush As Brush = New SolidBrush(DataGridTableSt yle.ForeCo lor)
If Me.DataGridTableStyle.Data Grid.IsSel ected(RowN um) Then
BackBrush = New SolidBrush(DataGridTableSt yle.Select ionBackCol or)
Else
BackBrush = New SolidBrush(DataGridTableSt yle.BackCo lor)
End If
PaintText(g, Bounds, Text, BackBrush, ForeBrush, RowNum, AlignToRight)
End Sub
Private Sub PaintText(ByVal g As Graphics, ByVal TextBounds As Rectangle, ByVal Text As String, ByVal BackBrush As Brush, _
ByVal ForeBrush As Brush, ByVal RowNum As Integer, 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.Directio nRightToLe ft
End If
Select Case Me.Alignment
Case HorizontalAlignment.Left
Format.Alignment = StringAlignment.Near
Case HorizontalAlignment.Right
Format.Alignment = StringAlignment.Far
Case HorizontalAlignment.Center
Format.Alignment = StringAlignment.Center
End Select
Format.FormatFlags = Format.FormatFlags Or StringFormatFlags.NoWrap
g.FillRectangle(Brush:=Bac kBrush, Rect:=Rect)
Rect.Offset(0, yMargin)
Rect.Height -= yMargin
g.DrawString(Text, Me.DataGridTableStyle.Data Grid.Font, ForeBrush, RectF, Format)
Format.Dispose()
End Sub
Private Sub DataGridComboBox_Enter(ByV al sender As Object, ByVal e As System.EventArgs)
Dim dG As DataGrid = Me.DataGridTableStyle.Data Grid
Me.cm = CType(dG.BindingContext(dG .DataSourc e, dG.DataMember), CurrencyManager)
'Prevent combo from setting to list position 0 on enter
If MyBase.GetColumnValueAtRow (cm, cm.Position) Is DBNull.Value Then
Me.Combo.SelectedIndex = -1
End If
End Sub
Private Sub DataGridComboBox_Leave(ByV al sender As Object, ByVal e As System.EventArgs)
If InEdit Then
If Me.Combo.SelectedIndex > -1 And cm.Position > -1 Then
SetColumnValueAtRow(cm, cm.Position, Me.Combo.SelectedValue)
End If
EndEdit()
End If
HideComboBox()
RaiseEvent Leave()
End Sub
Public Sub SetValue(ByVal value As Object)
If InEdit Then
If Me.Combo.SelectedIndex > -1 And cm.Position > -1 Then
SetColumnValueAtRow(cm, cm.Position, Me.Combo.SelectedValue)
End If
EndEdit()
Else
SetColumnValueAtRow(cm, cm.Position, value)
End If
Me.Combo.SelectedValue = value
HideComboBox()
RaiseEvent Leave()
End Sub
Private Sub DataGridComboBox_KeyPress( ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPr essEventAr gs)
If Char.IsLetterOrDigit(e.Key Char) Then
InEdit = True
MyBase.ColumnStartedEditin g(Me.Combo )
'Handle the optional autoDropDownOnEdit setting
If mDropDown Then
If Not Me.Combo.DroppedDown Then
Me.Combo.DroppedDown = True
End If
End If
End If
End Sub
Private Sub Combo_SelectedIndexChanged (ByVal sender As Object, ByVal e As System.EventArgs) Handles Combo.SelectedIndexChanged
InEdit = True
MyBase.ColumnStartedEditin g(Me.Combo )
End Sub
Private Sub Combo_DataSourceChanged(By Val sender As Object, ByVal e As System.EventArgs) Handles Combo.DataSourceChanged
If TypeOf (Me.Combo.DataSource) Is DataTable Then
Me.dV = CType(Me.Combo.DataSource, DataTable).DefaultView
ElseIf TypeOf (Me.Combo.DataSource) Is DataView Then
Me.dV = CType(Me.Combo.DataSource, DataView)
Else
Dim i As Integer = -1
End If
End Sub
Private Sub Combo_SelectedValueChanged (ByVal sender As Object, ByVal e As System.EventArgs) Handles Combo.SelectedValueChanged
RaiseEvent SelectedValue_Changed(send er, e)
End Sub
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
Inherits ComboBox
Public Sub New()
MyBase.New()
End Sub
Public isInEditOrNavigateMode As Boolean = True
Private setIndex As Int32
Private processCLOSEUP As Boolean = True
Private bForceFound As Boolean = False
Public Event ChangeIndex(ByVal sender As Object, ByVal e As System.EventArgs)
Const WM_KEYUP As Int32 = &H101
Const WM_KEYDOWN As Int32 = &H100
Const CBN_DROPDOWN As Int32 = &H7
Const CBN_CLOSEUP As Int32 = &H8
Const CBN_SELENDOK As Int32 = &H9
Const CBN_SELCHANGE As Int32 = &H1
Const WM_COMMAND As Int32 = &H111
Const WM_USER As Int32 = &H400
Const OCM__BASE As Int32 = WM_USER + &H1C00
Const OCM_COMMAND As Int32 = OCM__BASE + WM_COMMAND
Sub New(ByVal bForceFound As Boolean)
Me.bForceFound = bForceFound
End Sub
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Messa
Select Case m.Msg
Case OCM_COMMAND
Dim mIntPtr As Int32 = m.WParam.ToInt32
'Get notification of combobox list dropdown
'and enable setting index on list
'closeup
If (mIntPtr >> 16) = CBN_DROPDOWN Then
processCLOSEUP = True
End If
'If user selects an item in the list portion while dropped down
'disable setting index on closeup
If (mIntPtr >> 16) = CBN_SELENDOK Then
processCLOSEUP = False
End If
'If list portion is closing and user
'has not made a specific selection in
'the list area, set index
If processCLOSEUP Then
If (mIntPtr >> 16) = CBN_CLOSEUP Then
If Me.Items.Count > 0 Then
Me.SelectedIndex = setIndex
End If
End If
End If
End Select
MyBase.WndProc(m)
End Sub
Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Messa
Select Case msg.WParam.ToInt32()
Case CInt(Keys.Up)
If MyBase.Items.Count > 0 And MyBase.SelectedIndex > 0 Then
If MyBase.DroppedDown = False Then
MyBase.DroppedDown = True
End If
MyBase.SelectedIndex -= 1
setIndex = MyBase.SelectedIndex
End If
Return True
Case CInt(Keys.Down)
If MyBase.Items.Count > 0 And MyBase.SelectedIndex < MyBase.Items.Count - 1 Then
If MyBase.DroppedDown = False Then
MyBase.DroppedDown = True
processCLOSEUP = True
End If
MyBase.SelectedIndex += 1
setIndex = MyBase.SelectedIndex
End If
Return True
Case CInt(Keys.Right)
Return True
Case CInt(Keys.Left)
Return False
End Select
Return MyBase.ProcessCmdKey(msg, keyData)
End Function 'ProcessCmdKey
Protected Overrides Function ProcessKeymessage(ByRef m As System.Windows.Forms.Messa
'Handles the tab key skipping over columns
If m.Msg = WM_KEYUP Then
If m.WParam.ToInt32 = CInt(Keys.Tab) Then
Return True
ElseIf m.WParam.ToInt32 = CInt(Keys.Up) Or m.WParam.ToInt32 = CInt(Keys.Down) Then
'Combo_KeyDown(New Object, New KeyEventArgs(CType(m.WPara
Return True
Else
Return MyBase.ProcessKeyMessage(m
End If
Else
Return MyBase.ProcessKeyMessage(m
End If
End Function
Private Sub Combo_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEv
' Do nothing for certain keys such as navigation keys
With e
If ((e.KeyCode = Keys.Back) Or _
(.KeyCode = Keys.Enter) Or _
(.KeyCode = Keys.Left) Or _
(.KeyCode = Keys.Right) Or _
(.KeyCode = Keys.Up) Or _
(.KeyCode = Keys.Delete) Or _
(.KeyCode = Keys.Down) Or _
(.KeyCode = Keys.PageUp) Or _
(.KeyCode = Keys.PageDown) Or _
(.KeyCode = Keys.Home) Or _
(.KeyCode = Keys.ShiftKey) Or _
(.KeyCode = Keys.End) Or _
(.KeyCode = Keys.Tab AndAlso .KeyCode = Keys.Shift)) Then
Return
End If
End With
' Store the actual text that has been typed
Dim TypedText As String = Text
Dim index As Integer = FindString(TypedText)
' Get the text of the first match
If index > -1 Then
Dim foundText As String = Me.GetItemText(Items(index
Dim sAppendText As String = foundText.Substring(TypedT
Text = TypedText & sAppendText
' Select the portion of the text that was automatically
' added so further typing will replace it
SelectionStart = TypedText.Length
SelectionLength = sAppendText.Length
SelectedIndex = index
'For setting the the index using
'CBN_CLOSEUP notification (no user selection
'in dropped down list portion
If processCLOSEUP Then
Me.setIndex = index
End If
Else
'Enforces not in list
If bForceFound = True Then
ResetText()
End If
End If
End Sub
Private Sub Combo_SelectionChangeCommi
RaiseEvent ChangeIndex(sender, e)
End Sub
'Private Sub Combo_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEv
' If Me.Items.Count > 0 Then
' Select Case e.KeyCode
' Case Keys.Down
' If Me.SelectedIndex < Me.Items.Count - 1 Then
' Me.SelectedIndex += 1
' Else
' Me.SelectedIndex = 0
' End If
' Case Keys.Up
' If Me.SelectedIndex > 0 Then
' Me.SelectedIndex -= 1
' Else
' Me.SelectedIndex = Me.Items.Count - 1
' End If
' End Select
' End If
'End Sub
End Class
Public Class DataGridComboBoxColumnStyl
Inherits DataGridColumnStyle
'
' UI constants
'
Private xMargin As Integer = 2
Private yMargin As Integer = 0
'
'
Public WithEvents Combo As DataGridComboBox
Private m_DisplayMember, m_ValueMember As String
Private WithEvents cm As CurrencyManager
Private dV As New DataView
Private mDropDown As Boolean
'
' Used to track editing state
'
Private OldVal As String = String.Empty
Private InEdit As Boolean = False
Private bForceFound As Boolean
Private bAllowNew As Boolean
Public Event CreateNew(ByVal strText As String)
Public Event SelectedValue_Changed(ByVa
Public Event Leave()
#Region " New "
Public Sub New()
End Sub
' DATATABLE
' Create a new column - DisplayMember, ValueMember
' Passed by ordinal
'
Public Sub New(ByVal DataSource As DataTable, ByVal DisplayMember As Integer, ByVal ValueMember As Integer, ByVal _DropDownWidth As Integer, Optional ByVal bAllowNew As Boolean = True, Optional ByVal DropDownOnEdit As Boolean = True, Optional ByVal ForceFind As Boolean = False)
Me.bForceFound = ForceFind
Me.Combo = New DataGridComboBox(bForceFou
Me.bAllowNew = bAllowNew
InEdit = False
Me.m_DisplayMember = DataSource.Columns.Item(in
Me.m_ValueMember = DataSource.Columns.Item(in
With Me.Combo
.Visible = False
.DataSource = DataSource
.DisplayMember = m_DisplayMember
.ValueMember = m_ValueMember
.DropDownStyle = ComboBoxStyle.DropDown
.DropDownWidth = _DropDownWidth
.MaxDropDownItems = 20
mDropDown = DropDownOnEdit
AddHandler .Enter, AddressOf Me.DataGridComboBox_Enter
AddHandler .Leave, AddressOf DataGridComboBox_Leave
AddHandler .KeyPress, AddressOf DataGridComboBox_KeyPress
End With
Me.dV = DataSource.DefaultView
End Sub
' DATATABLE
' Create a new column - DisplayMember, ValueMember
' passed by string
'
Public Sub New(ByVal DataSource As DataTable, ByVal DisplayMember As String, ByVal ValueMember As String, ByVal _DropDownWidth As Integer, Optional ByVal bAllowNew As Boolean = True, Optional ByVal DropDownOnEdit As Boolean = True, Optional ByVal ForceFind As Boolean = False)
Me.bForceFound = ForceFind
Me.Combo = New DataGridComboBox(bForceFou
Me.bAllowNew = bAllowNew
InEdit = False
With Me.Combo
.Visible = False
.DataSource = DataSource
.DisplayMember = DisplayMember
.ValueMember = ValueMember
.DropDownStyle = ComboBoxStyle.DropDown
.DropDownWidth = _DropDownWidth
.MaxDropDownItems = 20
mDropDown = DropDownOnEdit
AddHandler .Enter, AddressOf Me.DataGridComboBox_Enter
AddHandler .Leave, AddressOf DataGridComboBox_Leave
AddHandler .KeyPress, AddressOf DataGridComboBox_KeyPress
End With
Me.dV = DataSource.DefaultView
End Sub
' DATVIEW
' Create a new column - DisplayMember, ValueMember
' Passed by ordinal
'
Public Sub New(ByVal DataSource As DataView, ByVal DisplayMember As Integer, ByVal ValueMember As Integer, ByVal _DropDownWidth As Integer, Optional ByVal bAllowNew As Boolean = True, Optional ByVal DropDownOnEdit As Boolean = True, Optional ByVal ForceFind As Boolean = False)
Me.bForceFound = ForceFind
Me.Combo = New DataGridComboBox(bForceFou
Me.bAllowNew = bAllowNew
InEdit = False
Me.m_DisplayMember = DataSource.Table.Columns.I
Me.m_ValueMember = DataSource.Table.Columns.I
With Me.Combo
.Visible = False
.DataSource = DataSource
.DisplayMember = m_DisplayMember
.ValueMember = m_ValueMember
.DropDownStyle = ComboBoxStyle.DropDown
.DropDownWidth = _DropDownWidth
.MaxDropDownItems = 20
mDropDown = DropDownOnEdit
AddHandler .Enter, AddressOf Me.DataGridComboBox_Enter
AddHandler .Leave, AddressOf DataGridComboBox_Leave
AddHandler .KeyPress, AddressOf DataGridComboBox_KeyPress
End With
Me.dV = DataSource
End Sub
' DATAVIEW
' Create a new column - DisplayMember, ValueMember
' passed by string
'
Public Sub New(ByVal DataSource As DataView, ByVal DisplayMember As String, ByVal ValueMember As String, ByVal _DropDownWidth As Integer, Optional ByVal bAllowNew As Boolean = True, Optional ByVal DropDownOnEdit As Boolean = True, Optional ByVal ForceFind As Boolean = False)
Me.bForceFound = ForceFind
Me.Combo = New DataGridComboBox(bForceFou
Me.bAllowNew = bAllowNew
InEdit = False
With Me.Combo
.Visible = False
.DataSource = DataSource
.DisplayMember = DisplayMember
.ValueMember = ValueMember
.DropDownStyle = ComboBoxStyle.DropDown
.DropDownWidth = _DropDownWidth
.MaxDropDownItems = 20
mDropDown = DropDownOnEdit
AddHandler .Enter, AddressOf Me.DataGridComboBox_Enter
AddHandler .Leave, AddressOf DataGridComboBox_Leave
AddHandler .KeyPress, AddressOf DataGridComboBox_KeyPress
End With
Me.dV = DataSource
End Sub
#End Region
'
'-------------------------
' Methods overridden from DataGridColumnStyle
'-------------------------
'
' Abort Changes
'
Protected Overloads Overrides Sub Abort(ByVal RowNum As Integer)
RollBack()
HideComboBox()
EndEdit()
End Sub
'
' Commit Changes
'
Protected Overloads Overrides Function Commit(ByVal DataSource As CurrencyManager, ByVal RowNum As Integer) As Boolean
If bForceFound = False And bAllowNew = True Then
Dim strFoundText As String = Me.Combo.Text
If Me.Combo.FindStringExact(s
If MessageBox.Show("Cannot find Item: '" & strFoundText & "'" & vbCrLf & "Would you like to create a new Item ?", "Create New", MessageBoxButtons.YesNo, MessageBoxIcon.Question) = DialogResult.Yes Then
RaiseEvent CreateNew(strFoundText)
InEdit = True
End If
End If
End If
HideComboBox()
If Not InEdit Then
Return True
End If
InEdit = False
Try
Dim Value As Object = Me.Combo.SelectedValue
If NullText.Equals(Value) Then
Value = Convert.DBNull
End If
SetColumnValueAtRow(DataSo
Catch ex As Exception
Debug.WriteLine(ex.ToStrin
RollBack()
Return False
End Try
EndEdit()
Return True
End Function
'
' Try to Handle SelectionChangeCommitted..
'
Protected Sub SelectionChanged(ByVal sender As Object, ByVal e As EventArgs) Handles Combo.ChangeIndex
' If the parent of the datagrid is a form...
If TypeOf (MyBase.DataGridTableStyle
' Get a reference to the form, to get the currencymanager.
Dim frm As Form = CType(MyBase.DataGridTable
' Get the currency manager associated with the form.
Dim cm As CurrencyManager = CType(frm.BindingContext(M
' Try and set the value.
Try
SetColumnValueAtRow(cm, MyBase.DataGridTableStyle.
Catch ex As Exception
Debug.WriteLine(ex.Message
End Try
End If
End Sub
'
' Edit Grid
'
Protected Overloads Overrides 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)
Try
With Me.Combo
'.Text = String.Empty
Dim OriginalBounds As Rectangle = Bounds
OldVal = .Text
If CellIsVisible Then
Bounds.Offset(xMargin, yMargin)
Bounds.Width -= xMargin * 2
Bounds.Height -= yMargin
.Bounds = Bounds
.Visible = True
Else
.Bounds = OriginalBounds
.Visible = False
End If
If .FindStringExact(.Text) > -1 Then
.SelectedValue = GetColumnValueAtRow(Source
Else
.SelectedIndex = -1
End If
If Not InstantText Is Nothing Then
.SelectedValue = InstantText
Else
.Select(.Text.Length, 0)
End If
.RightToLeft = Me.DataGridTableStyle.Data
.Focus()
If .Visible Then
Me.DataGridTableStyle.Data
End If
End With
InEdit = True
Catch ex As Exception
Debug.WriteLine(ex.ToStrin
InEdit = False
RollBack()
End Try
End Sub
Protected Overloads Overrides Function GetMinimumHeight() As Integer
Return Me.Combo.PreferredHeight + yMargin
End Function
Protected Overloads Overrides Function GetPreferredHeight(ByVal g As Graphics, _
ByVal Value As Object) As Integer
Dim NewLineIndex As Integer = 0
Dim NewLines As Integer = 0
Dim ValueString As String = Me.GetTxt(Value)
Do
While NewLineIndex <> -1
NewLineIndex = ValueString.IndexOf("r\n",
NewLines += 1
End While
Loop
Return FontHeight * NewLines + yMargin
End Function
Protected Overloads Overrides Function GetPreferredSize(ByVal g As Graphics, _
ByVal Value As Object) As Size
Dim Extents As Size = Size.Ceiling(g.MeasureStri
Me.DataGridTableStyle.Data
Extents.Width += xMargin * 2 + DataGridTableGridLineWidth
Extents.Height += yMargin
Return Extents
End Function
Protected Overloads Overrides 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(ByVal g As Graphics, _
ByVal Bounds As Rectangle, _
ByVal Source As CurrencyManager, _
ByVal RowNum As Integer, _
ByVal AlignToRight As Boolean)
Dim Text As String = GetTxt(GetColumnValueAtRow
PaintText(g, Bounds, Text, RowNum, AlignToRight)
End Sub
Protected Overloads 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 = GetTxt(GetColumnValueAtRow
PaintText(g, Bounds, Text, BackBrush, ForeBrush, RowNum, AlignToRight)
End Sub
Protected Overloads Overrides Sub SetDataGridInColumn(ByVal Value As DataGrid)
MyBase.SetDataGridInColumn
If Not (Me.Combo.Parent Is Value) Then
If Not (Me.Combo.Parent Is Nothing) Then
Me.Combo.Parent.Controls.R
End If
End If
If Not (Value Is Nothing) Then Value.Controls.Add(Me.Comb
End Sub
Protected Overloads Overrides Sub UpdateUI(ByVal Source As CurrencyManager, _
ByVal RowNum As Integer, ByVal InstantText As String)
If Not (InstantText Is Nothing) Then
Me.Combo.Text = InstantText
End If
End Sub
'-------------------------
' Helper Methods
'-------------------------
Private ReadOnly Property DataGridTableGridLineWidth
Get
If DataGridTableStyle.GridLin
Return 1
Else
Return 0
End If
End Get
End Property
Public Sub SetDataSource(ByVal dt As DataTable)
Me.Combo.DataSource = dt
End Sub
Private Sub EndEdit()
InEdit = False
Invalidate()
End Sub
Private Function GetTxt(ByVal s As Object) As String
Try
If s Is DBNull.Value Then Return NullText
If Not s Is Nothing Then
'Set up the delimiters for the search string based on TypeOf s
Dim strFilter As String = String.Empty
If TypeOf (Me.Combo.ValueMember) Is String Then
strFilter = "'" & s.ToString & "'"
ElseIf TypeOf (Me.Combo.ValueMember) Is DateTime Then
strFilter = "#" & s.ToString & "#"
Else
strFilter = s.ToString
End If
'Use datatable.select method
Dim drarr() As DataRow = Me.dV.Table.Select(Me.Comb
If drarr.Length > 0 Then 'Value found
'Return associated Display Member
Return drarr(0)(Me.Combo.DisplayM
Else 'Value NOT found
Return String.Empty
End If
Else
Return String.Empty
End If
Catch ex As Exception
Console.WriteLine(ex.ToStr
End Try
End Function
Private Sub HideComboBox()
If Me.Combo.Focused Then
Me.DataGridTableStyle.Data
End If
Me.Combo.Visible = False
End Sub
Private Sub RollBack()
Me.Combo.Text = OldVal
End Sub
Private Sub PaintText(ByVal g As Graphics, ByVal Bounds As Rectangle, ByVal Text As String, ByVal RowNum As Integer, _
ByVal AlignToRight As Boolean)
Dim BackBrush As Brush
Dim ForeBrush As Brush = New SolidBrush(DataGridTableSt
If Me.DataGridTableStyle.Data
BackBrush = New SolidBrush(DataGridTableSt
Else
BackBrush = New SolidBrush(DataGridTableSt
End If
PaintText(g, Bounds, Text, BackBrush, ForeBrush, RowNum, AlignToRight)
End Sub
Private Sub PaintText(ByVal g As Graphics, ByVal TextBounds As Rectangle, ByVal Text As String, ByVal BackBrush As Brush, _
ByVal ForeBrush As Brush, ByVal RowNum As Integer, 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.Directio
End If
Select Case Me.Alignment
Case HorizontalAlignment.Left
Format.Alignment = StringAlignment.Near
Case HorizontalAlignment.Right
Format.Alignment = StringAlignment.Far
Case HorizontalAlignment.Center
Format.Alignment = StringAlignment.Center
End Select
Format.FormatFlags = Format.FormatFlags Or StringFormatFlags.NoWrap
g.FillRectangle(Brush:=Bac
Rect.Offset(0, yMargin)
Rect.Height -= yMargin
g.DrawString(Text, Me.DataGridTableStyle.Data
Format.Dispose()
End Sub
Private Sub DataGridComboBox_Enter(ByV
Dim dG As DataGrid = Me.DataGridTableStyle.Data
Me.cm = CType(dG.BindingContext(dG
'Prevent combo from setting to list position 0 on enter
If MyBase.GetColumnValueAtRow
Me.Combo.SelectedIndex = -1
End If
End Sub
Private Sub DataGridComboBox_Leave(ByV
If InEdit Then
If Me.Combo.SelectedIndex > -1 And cm.Position > -1 Then
SetColumnValueAtRow(cm, cm.Position, Me.Combo.SelectedValue)
End If
EndEdit()
End If
HideComboBox()
RaiseEvent Leave()
End Sub
Public Sub SetValue(ByVal value As Object)
If InEdit Then
If Me.Combo.SelectedIndex > -1 And cm.Position > -1 Then
SetColumnValueAtRow(cm, cm.Position, Me.Combo.SelectedValue)
End If
EndEdit()
Else
SetColumnValueAtRow(cm, cm.Position, value)
End If
Me.Combo.SelectedValue = value
HideComboBox()
RaiseEvent Leave()
End Sub
Private Sub DataGridComboBox_KeyPress(
If Char.IsLetterOrDigit(e.Key
InEdit = True
MyBase.ColumnStartedEditin
'Handle the optional autoDropDownOnEdit setting
If mDropDown Then
If Not Me.Combo.DroppedDown Then
Me.Combo.DroppedDown = True
End If
End If
End If
End Sub
Private Sub Combo_SelectedIndexChanged
InEdit = True
MyBase.ColumnStartedEditin
End Sub
Private Sub Combo_DataSourceChanged(By
If TypeOf (Me.Combo.DataSource) Is DataTable Then
Me.dV = CType(Me.Combo.DataSource,
ElseIf TypeOf (Me.Combo.DataSource) Is DataView Then
Me.dV = CType(Me.Combo.DataSource,
Else
Dim i As Integer = -1
End If
End Sub
Private Sub Combo_SelectedValueChanged
RaiseEvent SelectedValue_Changed(send
End Sub
End Class
ASKER
Wow, thanks, I will try it out. Thanks again
ASKER
Thanks
http://www.syncfusion.com/FAQ/WindowsForms/FAQ_c44c.aspx#q888q