Multiple Column Listbox in VB.net

I'm a veteran Microsoft Access developer now working in vb.net.  To create a multiple column listbox with column headers in Access I simply had to set the ColumnCount property to the number of columns and the ColumnHeads property to "Yes".  Now using the listbox control in VB.net it looks like I only have an opportunity to specify one column of data to be displayed by setting the "DisplayMember" property.  Ultimately I need to present the user with a popup form the has 7 columns of data (there should never be more than 10 rows) and return a value (not displayed but associated to that row) after the user double clicks one of the rows).  I realize I could format the displayMember's data into tabbed columns myself, but have to believe there's a better way.  I also know about the multicolumn property but this is not what I need, for that just displays one column (i.e. field) of the datasource in multiple columns.  How else can I accomplish this in VB.net?  Is there a third party listbox control that I could use?  Would I be better off using the datagridview control to display multiple columns of data even though the user doesn't have to (in this case) edit the data but just has to double click one of the rows?
LVL 1
Declan_BasileITAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Najam UddinCommented:
Does this solves

ListView1.Columns.Add("Emp Name", 100, HorizontalAlignment.Left)
ListView1.Columns.Add("Emp Address", 150, HorizontalAlignment.Left)ListView1.Columns.Add("Title", 60, HorizontalAlignment.Left)
ListView1.Columns.Add("Salary", 50, HorizontalAlignment.Left)ListView1.Columns.Add("Department", 60, HorizontalAlignment.Left)

Open in new window

ArkCommented:
I suggest using datagridvie in readonly mode.
If you stay with listbox, you can use sql select statement with concat
select ColumnA + char(9) + ColumnB+ char(9) + ColumnC AS ConcatString 'MS-SQL
or select concat(ColumnA, "\t" ,ColumnB) AS ConcatString 'MySQL
Then set displaymember for ListBox to ConcatString
it_saigeDeveloperCommented:
You could use a ListBox (as you have alluded to) by using the DataProperty (or overriding the ToString() method) in order to produce the desired results.  However, it is not really columnized.  Your options at that point are to:

A.  Implement your own ListBox (refer to this CodeProject).
B.  Use a ListView in Details view mode.
C.  Use a DataGridView.
D.  Use a customized control; e.g. - ObjectListView

Each one has it's own pros and cons.

Form1.vb -
Imports System.ComponentModel

Public Class Form1
	ReadOnly people As New List(Of Person) From {New Person() With {.ID = 0, .Name = "Peter", .Birthdate = DateTime.Now, .IsWorking = True}}

	Private Sub OnLoad(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
		PopulateListBox()
		PopulateListView()
		PopulateDataGridView()
		PopulateObjectListView()
	End Sub

	Private Sub PopulateListBox()
		ListBox1.DataSource = people
	End Sub

	Private Sub PopulateListView()
		For Each p As Person In people
			Dim item As New ListViewItem(p.Name)
			item.SubItems.Add(p.Birthdate.ToShortDateString())
			item.SubItems.Add(p.IsWorking)
			ListView1.Items.Add(item)
		Next
	End Sub

	Private Sub PopulateDataGridView()
		DataGridView1.DataSource = people
	End Sub

	Private Sub PopulateObjectListView()
		ObjectListView1.DataSource = people
	End Sub
End Class

Class Person
	<Browsable(False)> _
	Public Property ID() As Integer
	Public Property Name() As String
	Public Property Birthdate() As DateTime
	Public Property IsWorking() As Boolean

	Public Overrides Function ToString() As String
		Return String.Format("ID: {0}; Name: {1}; Birthdate: {2}; Is Working: {3}", ID, Name, Birthdate.ToShortDateString(), IsWorking)
	End Function
End Class

Open in new window

Form1.Designer.vb -
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class Form1
    Inherits System.Windows.Forms.Form

    'Form overrides dispose to clean up the component list.
    <System.Diagnostics.DebuggerNonUserCode()> _
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            If disposing AndAlso components IsNot Nothing Then
                components.Dispose()
            End If
        Finally
            MyBase.Dispose(disposing)
        End Try
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    <System.Diagnostics.DebuggerStepThrough()> _
    Private Sub InitializeComponent()
		Me.ListView1 = New System.Windows.Forms.ListView()
		Me.ColName = CType(New System.Windows.Forms.ColumnHeader(), System.Windows.Forms.ColumnHeader)
		Me.ColBirthdate = CType(New System.Windows.Forms.ColumnHeader(), System.Windows.Forms.ColumnHeader)
		Me.ColIsWorking = CType(New System.Windows.Forms.ColumnHeader(), System.Windows.Forms.ColumnHeader)
		Me.ListBox1 = New System.Windows.Forms.ListBox()
		Me.DataGridView1 = New System.Windows.Forms.DataGridView()
		Me.Label1 = New System.Windows.Forms.Label()
		Me.Label2 = New System.Windows.Forms.Label()
		Me.Label3 = New System.Windows.Forms.Label()
		Me.ObjectListView1 = New BrightIdeasSoftware.DataListView()
		Me.Label4 = New System.Windows.Forms.Label()
		CType(Me.DataGridView1, System.ComponentModel.ISupportInitialize).BeginInit()
		CType(Me.ObjectListView1, System.ComponentModel.ISupportInitialize).BeginInit()
		Me.SuspendLayout()
		'
		'ListView1
		'
		Me.ListView1.Columns.AddRange(New System.Windows.Forms.ColumnHeader() {Me.ColName, Me.ColBirthdate, Me.ColIsWorking})
		Me.ListView1.Location = New System.Drawing.Point(11, 78)
		Me.ListView1.Name = "ListView1"
		Me.ListView1.Size = New System.Drawing.Size(618, 60)
		Me.ListView1.TabIndex = 0
		Me.ListView1.UseCompatibleStateImageBehavior = False
		Me.ListView1.View = System.Windows.Forms.View.Details
		'
		'ColName
		'
		Me.ColName.Text = "Name"
		'
		'ColBirthdate
		'
		Me.ColBirthdate.Text = "Birthdate"
		'
		'ColIsWorking
		'
		Me.ColIsWorking.Text = "IsWorking"
		'
		'ListBox1
		'
		Me.ListBox1.FormattingEnabled = True
		Me.ListBox1.Location = New System.Drawing.Point(12, 29)
		Me.ListBox1.Name = "ListBox1"
		Me.ListBox1.Size = New System.Drawing.Size(616, 30)
		Me.ListBox1.TabIndex = 1
		'
		'DataGridView1
		'
		Me.DataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize
		Me.DataGridView1.Location = New System.Drawing.Point(11, 157)
		Me.DataGridView1.Name = "DataGridView1"
		Me.DataGridView1.Size = New System.Drawing.Size(618, 60)
		Me.DataGridView1.TabIndex = 2
		'
		'Label1
		'
		Me.Label1.AutoSize = True
		Me.Label1.Location = New System.Drawing.Point(13, 13)
		Me.Label1.Name = "Label1"
		Me.Label1.Size = New System.Drawing.Size(47, 13)
		Me.Label1.TabIndex = 3
		Me.Label1.Text = "ListBox -"
		'
		'Label2
		'
		Me.Label2.AutoSize = True
		Me.Label2.Location = New System.Drawing.Point(13, 62)
		Me.Label2.Name = "Label2"
		Me.Label2.Size = New System.Drawing.Size(52, 13)
		Me.Label2.TabIndex = 6
		Me.Label2.Text = "ListView -"
		'
		'Label3
		'
		Me.Label3.AutoSize = True
		Me.Label3.Location = New System.Drawing.Point(13, 141)
		Me.Label3.Name = "Label3"
		Me.Label3.Size = New System.Drawing.Size(78, 13)
		Me.Label3.TabIndex = 7
		Me.Label3.Text = "DataGridView -"
		'
		'ObjectListView1
		'
		Me.ObjectListView1.DataSource = Nothing
		Me.ObjectListView1.Location = New System.Drawing.Point(11, 236)
		Me.ObjectListView1.Name = "ObjectListView1"
		Me.ObjectListView1.Size = New System.Drawing.Size(618, 98)
		Me.ObjectListView1.TabIndex = 0
		Me.ObjectListView1.UseCompatibleStateImageBehavior = False
		Me.ObjectListView1.View = System.Windows.Forms.View.Details
		'
		'Label4
		'
		Me.Label4.AutoSize = True
		Me.Label4.Location = New System.Drawing.Point(13, 220)
		Me.Label4.Name = "Label4"
		Me.Label4.Size = New System.Drawing.Size(83, 13)
		Me.Label4.TabIndex = 8
		Me.Label4.Text = "ObjectListView -"
		'
		'Form1
		'
		Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
		Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
		Me.ClientSize = New System.Drawing.Size(640, 346)
		Me.Controls.Add(Me.Label4)
		Me.Controls.Add(Me.ObjectListView1)
		Me.Controls.Add(Me.Label3)
		Me.Controls.Add(Me.Label2)
		Me.Controls.Add(Me.Label1)
		Me.Controls.Add(Me.DataGridView1)
		Me.Controls.Add(Me.ListBox1)
		Me.Controls.Add(Me.ListView1)
		Me.Name = "Form1"
		Me.Text = "Form1"
		CType(Me.DataGridView1, System.ComponentModel.ISupportInitialize).EndInit()
		CType(Me.ObjectListView1, System.ComponentModel.ISupportInitialize).EndInit()
		Me.ResumeLayout(False)
		Me.PerformLayout()

	End Sub
	Friend WithEvents ListView1 As System.Windows.Forms.ListView
	Friend WithEvents ListBox1 As System.Windows.Forms.ListBox
	Friend WithEvents DataGridView1 As System.Windows.Forms.DataGridView
	Friend WithEvents Label1 As System.Windows.Forms.Label
	Friend WithEvents Label2 As System.Windows.Forms.Label
	Friend WithEvents Label3 As System.Windows.Forms.Label
	Friend WithEvents ObjectListView1 As BrightIdeasSoftware.DataListView
	Friend WithEvents Label4 As System.Windows.Forms.Label
	Friend WithEvents ColName As System.Windows.Forms.ColumnHeader
	Friend WithEvents ColBirthdate As System.Windows.Forms.ColumnHeader
	Friend WithEvents ColIsWorking As System.Windows.Forms.ColumnHeader

End Class

Open in new window

Which produces the following output -Capture.JPG-saige-

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
ArkCommented:
If you replace your overrided ToString method with (VB doesn't understand char literals)
Return String.Format("{0}\t{1}\t{2}\t{3}", ID, Name, Birthdate.ToShortDateString(), IsWorking).Replace("\t", vbTab)

Open in new window

you'll see columns in a listbox
You can specify column width
ListBox1.UseCustomTabOffsets = True
ListBox1.CustomTabOffsets.AddRange(New Integer() {50, 100})

Open in new window

Knowing column width you can add "headers" as labels above listbox
Declan_BasileITAuthor Commented:
The DataGridView worked well for me.  Thank you.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic.NET

From novice to tech pro — start learning today.