Link to home
Start Free TrialLog in
Avatar of Joseph Jones
Joseph JonesFlag for Australia

asked on

How to have more than 1 column in a combobox and populate values to multicolumns

I want to have a combobox which should populate Customer Name, CustomerID and DateOfBirth.
Therefore, my combobox should have three columns and the values for each columns should be filled after running a sqlreader.
Thanks
Avatar of Slow_mo
Slow_mo

You will have to use a custom combobox control, as a standard one does not allow to have more than one column.
Try if this works: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=140260&SiteID=1
Avatar of Joseph Jones

ASKER

Hi
After creating the usercontrol using the code in the above link,  I have the following error.  I believe this code was written for vb.net 2003 but I need it for vb.net 2005.

Imports System.Windows
 
Public Class MultiColumnCombo
 
    Inherits System.Windows.Forms.ComboBox
 
    Private _ColumnWidths As String = "100"
 
    Private _ColumnWidthsArray As String()
 
    Private _DoNotReact As Boolean = False
 
    Private _Textchanged As Boolean = False
 
    Sub New()
 
        MyBase.New()
 
        MyBase.DrawMode = Forms.DrawMode.OwnerDrawFixed
 
        'SetStyle(ControlStyles.UserPaint, True)
 
        'SetStyle(ControlStyles.AllPaintingInWmPaint, True)
 
        'SetStyle(ControlStyles.DoubleBuffer, True)
 
    End Sub
 
 
 
 
 
    Public Property ColumnWidths() As String
 
        Get
 
            Return _ColumnWidths
 
        End Get
 
        Set(ByVal Value As String)
 
            _ColumnWidths = Value
 
            _ColumnWidthsArray = Value.Split(CType(";", Char))
 
            Dim w As Integer = 0
 
            For Each str As String In _ColumnWidthsArray
 
                w += CInt(str)
 
            Next str
 
            MyBase.DropDownWidth = w + 10
 
        End Set
 
    End Property
 
 
 
    Protected Overrides Sub OnDrawItem(ByVal e As System.Windows.Forms.DrawItemEventArgs)
 
        ' Set the DrawMode property to draw fixed sized items.
 
 
 
        ' 
 
        'If _Textchanged Then
 
        '    _Textchanged = False
 
        '    Exit Sub
 
        'End If
 
 
 
        Dim myBrush As Brush
 
        'If e.Bounds.Y = 0 Then
 
        '    ItemHeight = 32
 
        'Else
 
        '    ItemHeight = 16
 
        'End If
 
        '  e.DrawBackground()
 
        Dim LightColor As Color = Color.Blue
 
        Dim DarkColor As Color = Color.Black
 
        Dim GradBrush As Brush = New Drawing2D.LinearGradientBrush(e.Bounds, LightColor, DarkColor, Drawing2D.LinearGradientMode.Vertical)
 
 
 
 
 
 
 
        Select Case CInt((e.State And DrawItemState.Selected))
 
            'Case DrawItemState.Selected + DrawItemState.NoAccelerator + DrawItemState.NoFocusRect, DrawItemState.Selected
 
            Case DrawItemState.Selected
 
                myBrush = New SolidBrush(BackColor)
 
                e.Graphics.FillRectangle(GradBrush, e.Bounds)
 
            Case Else
 
                myBrush = New SolidBrush(ForeColor)
 
                'myBrush = GradBrush
 
                e.Graphics.FillRectangle(New SolidBrush(BackColor), e.Bounds)
 
        End Select
 
 
 
 
 
 
 
        Dim str As String
 
        ' Draw the current item text based on the current Font and the custom brush settings.
 
        Dim row As DataRowView = (CType(MyBase.Items(e.Index), DataRowView))
 
        Dim newpos As Integer = e.Bounds.X
 
        Dim endpos As Integer = e.Bounds.X
 
 
 
        For indx As Integer = 0 To UBound(_ColumnWidthsArray)
 
            Dim ColLength As Integer = CType(_ColumnWidthsArray(indx), Integer)
 
            endpos += ColLength
 
 
 
            Dim Charaant As Integer = CInt(Math.Round(CDbl(ColLength) / 6.2))
 
            Dim rawitem As String = row.Item(indx).ToString()
 
 
 
            If ColLength <> 0 Then
 
 
 
 
 
                If Charaant > rawitem.Length Then
 
                    str = rawitem
 
 
 
                Else
 
 
 
                    str = rawitem.Substring(0, Charaant)
 
                End If
 
 
 
                Dim r As RectangleF = New RectangleF(newpos + 2, e.Bounds.Y, endpos - 1, e.Bounds.Height)
 
 
 
                'e.Graphics.FillRectangle(myBrush, r)
 
 
 
                e.Graphics.DrawString(str, e.Font, myBrush, r)
 
 
 
                'ControlPaint.DrawBorder3D(e.Graphics, New Rectangle(endpos + 2, e.Bounds.Y, newpos, e.Bounds.Height))
 
                'e.Graphics.DrawString("mycol", e.Font, myBrush, New RectangleF(newpos, 0, CInt(_ColumnWidthsArray(indx)), ItemHeight))
 
                If indx <= UBound(_ColumnWidthsArray) Then
 
                    e.Graphics.DrawLine(New Pen(Color.Black), endpos, e.Bounds.Y, endpos, Me.ItemHeight * Me.MaxDropDownItems)
 
                    e.Graphics.DrawLine(New Pen(Color.LightGray), endpos + 1, e.Bounds.Y, endpos + 1, Me.ItemHeight * Me.MaxDropDownItems)
 
                End If
 
            End If
 
 
 
            newpos = endpos
 
        Next
 
        '        e.DrawFocusRectangle()
 
        myBrush.Dispose()
 
        GradBrush.Dispose()
 
 
 
 
 
    End Sub
 
 
 
    Protected Overrides Sub OnTextChanged(ByVal e As System.EventArgs)
 
 
 
        Dim foundIndex As Integer, textlngth As Integer
 
        If _DoNotReact = False Then
 
            If Me.AccessibilityObject.Value Is Nothing Then
 
                textlngth = 0
 
                Exit Sub
 
            Else
 
                textlngth = Me.AccessibilityObject.Value.Length
 
            End If
 
 
 
            If textlngth = 0 Then
 
                MyBase.OnTextChanged(e)
 
                _DoNotReact = False
 
                _Textchanged = False
 
                Exit Sub
 
            End If
 
 
 
            If textlngth <> 0 Then
 
 
 
                _DoNotReact = True
 
                foundIndex = FindString(Me.AccessibilityObject.Value)
 
                If foundIndex > -1 Then
 
                    Me.SelectedIndex = foundIndex
 
                    Me.Select(textlngth, Me.Text.Length - textlngth)
 
                    'Me.SelectionStart = textlngth
 
                    _Textchanged = True
 
                Else
 
                    _Textchanged = False
 
                End If
 
                _DoNotReact = False
 
            End If
 
            MyBase.OnTextChanged(e)
 
        End If
 
        _DoNotReact = False
 
 
 
 
 
 
 
    End Sub
 
 
 
    Protected Overrides Sub OnKeyDown(ByVal e As System.Windows.Forms.KeyEventArgs)
 
        Select Case e.KeyCode
 
            Case Keys.Back, Keys.Enter, Keys.Delete
 
                _DoNotReact = True
 
            Case Keys.Down
 
                Me.DroppedDown = True
 
                Invalidate()
 
 
 
        End Select
 
 
 
        MyBase.OnKeyDown(e)
 
 
 
    End Sub
 
 
 
    Protected Overrides Sub Finalize()
        MyBase.Finalize()
    End Sub
End Class

Open in new window

This works on VB.2005
You must add an Accessibility reference to project
Imports System.Windows
 
Public Class MultiColumnCombo
 
    Inherits System.Windows.Forms.ComboBox
 
    Private _ColumnWidths As String = "100"
 
    Private _ColumnWidthsArray As String()
 
    Private _DoNotReact As Boolean = False
 
    Private _Textchanged As Boolean = False
 
    Sub New()
 
        MyBase.New()
 
        MyBase.DrawMode = Forms.DrawMode.OwnerDrawFixed
 
        'SetStyle(ControlStyles.UserPaint, True)
 
        'SetStyle(ControlStyles.AllPaintingInWmPaint, True)
 
        'SetStyle(ControlStyles.DoubleBuffer, True)
 
    End Sub
 
 
    Public Property ColumnWidths() As String
 
        Get
 
            Return _ColumnWidths
 
        End Get
 
        Set(ByVal Value As String)
 
            _ColumnWidths = Value
 
            _ColumnWidthsArray = Value.Split(CType(";", Char))
 
            Dim w As Integer = 0
 
            For Each str As String In _ColumnWidthsArray
 
                w += CInt(str)
 
            Next str
 
            MyBase.DropDownWidth = w + 10
 
        End Set
 
    End Property
 
 
 
    Protected Overrides Sub OnDrawItem(ByVal e As System.Windows.Forms.DrawItemEventArgs)
 
        ' Set the DrawMode property to draw fixed sized items.
 
 
 
        ' 
 
        'If _Textchanged Then
 
        '    _Textchanged = False
 
        '    Exit Sub
 
        'End If
 
 
 
        Dim myBrush As Brush
 
        'If e.Bounds.Y = 0 Then
 
        '    ItemHeight = 32
 
        'Else
 
        '    ItemHeight = 16
 
        'End If
 
        '  e.DrawBackground()
 
        Dim LightColor As Color = Color.Blue
 
        Dim DarkColor As Color = Color.Black
 
        Dim GradBrush As Brush = New Drawing2D.LinearGradientBrush(e.Bounds, LightColor, DarkColor, Drawing2D.LinearGradientMode.Vertical)
 
 
        Select Case CInt((e.State And DrawItemState.Selected))
 
            'Case DrawItemState.Selected + DrawItemState.NoAccelerator + DrawItemState.NoFocusRect, DrawItemState.Selected
 
            Case DrawItemState.Selected
 
                myBrush = New SolidBrush(BackColor)
 
                e.Graphics.FillRectangle(GradBrush, e.Bounds)
 
            Case Else
 
                myBrush = New SolidBrush(ForeColor)
 
                'myBrush = GradBrush
 
                e.Graphics.FillRectangle(New SolidBrush(BackColor), e.Bounds)
 
        End Select
 
 
        Dim str As String
 
        ' Draw the current item text based on the current Font and the custom brush settings.
 
        Dim row As DataRowView = (CType(MyBase.Items(e.Index), DataRowView))
 
        Dim newpos As Integer = e.Bounds.X
 
        Dim endpos As Integer = e.Bounds.X
 
 
 
        For indx As Integer = 0 To UBound(_ColumnWidthsArray)
 
            Dim ColLength As Integer = CType(_ColumnWidthsArray(indx), Integer)
 
            endpos += ColLength
 
 
 
            Dim Charaant As Integer = CInt(Math.Round(CDbl(ColLength) / 6.2))
 
            Dim rawitem As String = row.Item(indx).ToString()
 
 
 
            If ColLength <> 0 Then
 
 
 
 
 
                If Charaant > rawitem.Length Then
 
                    str = rawitem
 
 
 
                Else
 
 
 
                    str = rawitem.Substring(0, Charaant)
 
                End If
 
 
 
                Dim r As RectangleF = New RectangleF(newpos + 2, e.Bounds.Y, endpos - 1, e.Bounds.Height)
 
 
 
                'e.Graphics.FillRectangle(myBrush, r)
 
 
 
                e.Graphics.DrawString(str, e.Font, myBrush, r)
 
 
 
                'ControlPaint.DrawBorder3D(e.Graphics, New Rectangle(endpos + 2, e.Bounds.Y, newpos, e.Bounds.Height))
 
                'e.Graphics.DrawString("mycol", e.Font, myBrush, New RectangleF(newpos, 0, CInt(_ColumnWidthsArray(indx)), ItemHeight))
 
                If indx <= UBound(_ColumnWidthsArray) Then
 
                    e.Graphics.DrawLine(New Pen(Color.Black), endpos, e.Bounds.Y, endpos, Me.ItemHeight * Me.MaxDropDownItems)
 
                    e.Graphics.DrawLine(New Pen(Color.LightGray), endpos + 1, e.Bounds.Y, endpos + 1, Me.ItemHeight * Me.MaxDropDownItems)
 
                End If
 
            End If
 
 
 
            newpos = endpos
 
        Next
 
        '        e.DrawFocusRectangle()
 
        myBrush.Dispose()
 
        GradBrush.Dispose()
 
    End Sub
 
 
 
    Protected Overrides Sub OnTextChanged(ByVal e As System.EventArgs)
 
 
 
        Dim foundIndex As Integer, textlngth As Integer
 
        If _DoNotReact = False Then
 
            If Me.AccessibilityObject.Value Is Nothing Then
 
                textlngth = 0
 
                Exit Sub
 
            Else
 
                textlngth = Me.AccessibilityObject.Value.Length
 
            End If
 
 
 
            If textlngth = 0 Then
 
                MyBase.OnTextChanged(e)
 
                _DoNotReact = False
 
                _Textchanged = False
 
                Exit Sub
 
            End If
 
 
 
            If textlngth <> 0 Then
 
 
 
                _DoNotReact = True
 
                foundIndex = FindString(Me.AccessibilityObject.Value)
 
                If foundIndex > -1 Then
 
                    Me.SelectedIndex = foundIndex
 
                    Me.Select(textlngth, Me.Text.Length - textlngth)
 
                    'Me.SelectionStart = textlngth
 
                    _Textchanged = True
 
                Else
 
                    _Textchanged = False
 
                End If
 
                _DoNotReact = False
 
            End If
 
            MyBase.OnTextChanged(e)
 
        End If
 
        _DoNotReact = False
 
 
    End Sub
 
 
 
    Protected Overrides Sub OnKeyDown(ByVal e As System.Windows.Forms.KeyEventArgs)
 
        Select Case e.KeyCode
 
            Case Keys.Back, Keys.Enter, Keys.Delete
 
                _DoNotReact = True
 
            Case Keys.Down
 
                Me.DroppedDown = True
 
                Invalidate()
 
 
 
        End Select
        MyBase.OnKeyDown(e)
    End Sub
 
 
 
    Protected Overrides Sub Finalize()
        MyBase.Finalize()
    End Sub
End Class

Open in new window

Hi
Now the multicolumcombobox is created in my form but when you add values to the columns, it generates the following error message.

"Unable to cast object of type 'System.String' to type 'System.Data.DataRowView'."

under code:

Dim row As DataRowView = (CType(MyBase.Items(e.Index), DataRowView))

Can you please check this to fix this problem?

Thanks
That's because this control must be assigned a DataSource which is a table. I tried that and to be honest, did not quite like the control.

Maybe try this one. It comes with example:
http://www.codeproject.com/KB/cpp/multicolumncombo.aspx
Hi
After downloading the zip file, I convert the project into vb.2005 and then when I tried to run the project, it generated the following error message:

"A Project with out Output Type of Class Library can not be started directly.
In order to debug this project, add an executable project to this solution which
references  the library project.  Set the executable project as the startup project."

I don't know how to fix it...!!!
Hi
Is anybody there to fix this problem?
Thanks
ASKER CERTIFIED SOLUTION
Avatar of Slow_mo
Slow_mo

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial