הערה
הגישה לדף זה מחייבת הרשאה. באפשרותך לנסות להיכנס או לשנות מדריכי כתובות.
הגישה לדף זה מחייבת הרשאה. באפשרותך לנסות לשנות מדריכי כתובות.
Question
Thursday, September 7, 2017 2:04 AM | 1 vote
I would like to use multiple columns in databound combo boxes and/or list boxes. What are the properties required to do this?
gwboolean
All replies (16)
Thursday, September 7, 2017 7:17 AM ✅Answered | 2 votes
Hi gwboolean,
Do you want to do like this:
You can do this by Combobox_DrawItem event, like this:
Private Sub Form7_Load(sender As Object, e As EventArgs) Handles MyBase.Load
fun()
ComboBox1.DrawMode = DrawMode.OwnerDrawVariable
End Sub
Dim dt As New DataTable
Private Sub fun()
Dim str As String = "Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=D:\C# and VB Support\Example(VB)\Demo\Data3.mdf;Integrated Security=True;Connect Timeout=30"
Dim conn As New SqlConnection(str)
conn.Open()
Dim sql As String = "select ID,ProductName,Vendor,Material from Test12"
Dim cmd As New SqlCommand(sql, conn)
Dim adapter As New SqlDataAdapter(cmd)
'fill data into dataset
adapter.Fill(dt)
ComboBox1.DisplayMember = "ID"
ComboBox1.DataSource = dt
End Sub
Private Sub ComboBox1_DrawItem(sender As Object, e As DrawItemEventArgs) Handles ComboBox1.DrawItem
e.DrawBackground()
Dim drv As DataRowView = DirectCast(ComboBox1.Items(e.Index), DataRowView)
Dim id As String = drv("ID").ToString()
Dim productname As String = drv("ProductName").ToString()
Dim Vendor As String = drv("Vendor").ToString()
Dim material As String = drv("Material").ToString()
Dim r1 As Rectangle = e.Bounds
r1.Width = r1.Width / 4
Using sb As New SolidBrush(Color.Black)
e.Graphics.DrawString(id, e.Font, sb, r1)
End Using
'Using p As New Pen(Color.AliceBlue)
' e.Graphics.DrawLine(p, r1.Right, 0, r1.Right, r1.Bottom)
'End Using
Dim r2 As Rectangle = e.Bounds
r2.X = e.Bounds.Width / 8
r2.Width = r2.Width / 4
Using sb As New SolidBrush(Color.Black)
e.Graphics.DrawString(productname, e.Font, sb, r2)
End Using
'Using p As New Pen(Color.AliceBlue)
' e.Graphics.DrawLine(p, r2.Right, 0, r2.Right, r2.Bottom)
'End Using
Dim r3 As Rectangle = e.Bounds
r3.X = e.Bounds.Width / 3
r3.Width = r3.Width / 4
Using sb As New SolidBrush(Color.Black)
e.Graphics.DrawString(Vendor, e.Font, sb, r3)
End Using
'Using p As New Pen(Color.AliceBlue)
' e.Graphics.DrawLine(p, r3.Right, 0, r3.Right, r3.Bottom)
'End Using
Dim r4 As Rectangle = e.Bounds
r4.X = e.Bounds.Width / 1.5
r4.Width = r4.Width / 4
Using sb As New SolidBrush(Color.Black)
e.Graphics.DrawString(material, e.Font, sb, r4)
End Using
End Sub
Best Regards,
Cherry
MSDN Community Support
Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.
Thursday, September 7, 2017 9:56 AM ✅Answered | 2 votes
Here is a custom ComboBox done in C#, shown below in vb.net.
Imports System.Drawing.Drawing2D
<ComponentModel.DesignerCategoryAttribute("Code")>
Public Class MultiColumnCombo
Inherits ComboBox
Private MyColumnWidths As String = "100"
Private mColumnWidths As String()
Private DoNotReact As Boolean = False
Private TextHasChanged As Boolean = False
Sub New()
MyBase.New()
DrawMode = DrawMode.Normal
SetStyle(ControlStyles.AllPaintingInWmPaint, True)
SetStyle(ControlStyles.DoubleBuffer, True)
End Sub
Public Property ColumnWidths() As String
Get
Return MyColumnWidths
End Get
Set(ByVal Value As String)
MyColumnWidths = Value
mColumnWidths = Value.Split(CType(";", Char))
Dim FinalWidth As Integer = 0
For Each ColumnWidth As String In mColumnWidths
FinalWidth += CInt(ColumnWidth)
Next ColumnWidth
MyBase.DropDownWidth = FinalWidth + 10
End Set
End Property
<DebuggerStepThrough()>
Protected Overrides Sub OnDrawItem(ByVal e As System.Windows.Forms.DrawItemEventArgs)
Dim myBrush As Brush
Dim LightColor As Color = Color.Blue
Dim DarkColor As Color = Color.Black
Dim GradBrush As Brush = New LinearGradientBrush(e.Bounds,
LightColor,
DarkColor,
LinearGradientMode.Horizontal)
Select Case CInt((e.State And DrawItemState.Selected))
Case DrawItemState.Selected
myBrush = New SolidBrush(BackColor)
e.Graphics.FillRectangle(GradBrush, e.Bounds)
Case Else
myBrush = New SolidBrush(ForeColor)
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(mColumnWidths)
Dim ColLength As Integer = CType(mColumnWidths(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.DrawString(str, e.Font, myBrush, r)
If indx <= UBound(mColumnWidths) 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
<DebuggerStepThrough()>
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
TextHasChanged = 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)
TextHasChanged = True
Else
TextHasChanged = 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
DroppedDown = True
Invalidate()
End Select
MyBase.OnKeyDown(e)
End Sub
End Class
Usage after compiling and placing the control on a form, note all that matters for loading is we have a DataTable.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim dataTable As New DataTable("Employees")
dataTable.Columns.Add("Employee ID", GetType(String))
dataTable.Columns.Add("Name", GetType(String))
dataTable.Columns.Add("Designation", GetType(String))
dataTable.Rows.Add(New String() {"D1", "Natalia", "Developer"})
dataTable.Rows.Add(New String() {"D2", "Jonathan", "Developer"})
dataTable.Rows.Add(New String() {"D3", "Jake", "Developer"})
dataTable.Rows.Add(New String() {"D4", "Abraham", "Developer"})
dataTable.Rows.Add(New String() {"T1", "Mary", "Team Lead"})
dataTable.Rows.Add(New String() {"PM1", "Calvin", "Project Manager"})
dataTable.Rows.Add(New String() {"T2", "Sarah", "Team Lead"})
dataTable.Rows.Add(New String() {"D12", "Monica", "Developer"})
dataTable.Rows.Add(New String() {"D13", "Donna", "Developer"})
MultiColumnCombo1.DataSource = dataTable
MultiColumnCombo1.DisplayMember = "Employee ID"
MultiColumnCombo1.ValueMember = "Name"
MultiColumnCombo1.ColumnWidths = "100;100"
End Sub
Note you adjust column width via the last line of code above. Also need to set the following
Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
VB Forums - moderator
Thursday, September 7, 2017 3:18 AM
I would like to use multiple columns in databound combo boxes and/or list boxes. What are the properties required to do this?
The ListBox MultiColumn property will arrange your items in as many columns as required to avoid scrolling. See:
https://msdn.microsoft.com/en-us/library/system.windows.forms.listbox.multicolumn(v=vs.110).aspx
Thursday, September 7, 2017 4:04 AM
Thanks Acamar, that is perfect. Would you happen to be able to pull one like that for a combo box out of your pocket as well?
gwboolean
Thursday, September 7, 2017 4:39 AM
Thanks Acamar, that is perfect. Would you happen to be able to pull one like that for a combo box out of your pocket as well?
Something like this?
https://support.microsoft.com/en-au/help/982498/how-to-create-a-multiple-column-drop-down-list-for-a-combo-box-in-wind
That may need some small adjustments for a WIndows Forms project.
This does not come from any private source. Generally speaking, if you type the topic of the post into your favourite search engine together with '.net' or 'visual basic .net' then you will see a number of likely solutions.
Thursday, September 7, 2017 6:44 AM
Acamar,
I could not find any information about a multi column combobox on that page you gave.
Success
Cor
Thursday, September 7, 2017 7:03 AM
A multicolumn listbox is a datagridview with the Horizontal and vertical headers set to false.
For the same combobox (and not a horizontal shown multi column combobox) you can search Internet it is not default in the Microsoft range.
(Or buy 3rd party controls).
Success
Cor
Thursday, September 7, 2017 9:59 AM
A multicolumn listbox is a datagridview with the Horizontal and vertical headers set to false.
For the same combobox (and not a horizontal shown multi column combobox) you can search Internet it is not default in the Microsoft range.
(Or buy 3rd party controls).
Success
Cor
I agree that a DataGridView or third party control is a good solution for no hassles.
Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
VB Forums - moderator
Thursday, September 7, 2017 5:47 PM
Cherry,
I have tried working through your methodology, but I lose it at the line:
Dim conn As New SqlConnection(str)
I am using an Access Dataset and am unable to find an equivalent command for the connection string.
gwboolean
Thursday, September 7, 2017 5:53 PM
Karen,
I can see that in your methodology you create a data table with defined/declared rows and data.
I am using an existing table and I would assume that I would need a loop that carries me through the table. I would probably need to filter the table to get a desired subgroup as well.
Anyway, could you show me how to use an existing table?
You know, I am beginning to think a datagridview might be the best answer, as you suggest.
Thanks
gwboolean
Thursday, September 7, 2017 5:56 PM
Cherry,
I have tried working through your methodology, but I lose it at the line:
Dim conn As New SqlConnection(str)
I am using an Access Dataset and am unable to find an equivalent command for the connection string.
gwboolean
That has nothing to do with the combobox.
However, the equal code for an MS Access database is
Dim conn as New OleDbConnection(str)
Success
Cor
Thursday, September 7, 2017 6:12 PM
I do understand that Cor. But thanks for the appropriate statement for my dataset.
gwboolean
Thursday, September 7, 2017 6:38 PM
Karen,
I can see that in your methodology you create a data table with defined/declared rows and data.
I am using an existing table and I would assume that I would need a loop that carries me through the table. I would probably need to filter the table to get a desired subgroup as well.
Anyway, could you show me how to use an existing table?
You know, I am beginning to think a datagridview might be the best answer, as you suggest.
Thanks
gwboolean
It does not matter if I used the method shown in my code sample or via loading from a database table.
So here is random example of loading a DataTable from a table in a database.
Public Class Sample
Private Builder As New OleDbConnectionStringBuilder With
{
.Provider = "Microsoft.ACE.OLEDB.12.0",
.DataSource = IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DatabaseKu.accdb")
}
Public Function ReadUserData(ByVal UserName As String, ByVal UserPassword As String) As DataTable
Dim dt As New DataTable
Using cn As New OleDbConnection With {.ConnectionString = Builder.ConnectionString}
Using cmd As New OleDbCommand With {.Connection = cn}
cmd.CommandText =
<SQL>
SELECT * FROM LOGIN WHERE username = @UserName, [password] = @password
</SQL>.Value
cmd.Parameters.AddWithValue("@UserName", UserName)
cmd.Parameters.AddWithValue("@password", UserPassword)
cn.Open()
dt.Load(cmd.ExecuteReader)
End Using
End Using
Return dt
End Function
End Class
In the above I would set the DataTable returned from the function same as I did in my first example.
Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
VB Forums - moderator
Thursday, September 7, 2017 7:18 PM
I get that. I was just looking to see what it looks like to do it that way. However, I can see that the way I thought I should code to display from a table is not correct.
You guys always assume that I know more than I know. I don't know what I don't know.
Thanks Karen
gwboolean
Friday, September 8, 2017 2:28 PM
I get that. I was just looking to see what it looks like to do it that way. However, I can see that the way I thought I should code to display from a table is not correct.
You guys always assume that I know more than I know. I don't know what I don't know.
Thanks Karen
gwboolean
GWBoolean,
What is your purpose of this, the reply you marked as answer has absolute nothing to do with the question.
I think you want less replies I gues, because this is quite offending.
Success
Cor
Friday, September 8, 2017 4:40 PM
Sorry Cor, I was not really paying attention and perhaps clicked the wrong one. I did not know it mattered. At any rate, I went back and changed it to the replies that provided the information that I was able to use.
I am not sure why this would be offensive to anyone.
gwboolean