Renumbering a Work Breakdown Structure (WBS) in a datatable - vb.net

A multi-level WBS the users were able to delete some tasks that are not applicable to their project. Goal is to renumber the entire WBS so that no numbers are skipped. Example: 1.1.1, 1.1.2, 1.1.4 - number 1.1.3 was deleted. Each WBS element may or may not have child elements that need to be renumbered as well.
I have the data in a datatable, fields: WBS_ID, WBSNo, ParentID, ParentNo, SortKey(the original WBS Number) and Notes. WBS_ID is the UID, ParentID is the WBS_ID of the parent WBS element. First element of the WBS has a null value in the ParentID field.
I cannot seem to grasp how to make an iterative function call to create the WBS number.
Dim dTb As New DataTable
Using Conn
Conn.Open()
Using dad As New SqlClient.SqlDataAdapter(vSqlStr, Conn)
dad.SelectCommand.Parameters.Add("#ProjectID", SqlDbType.Int)
dad.SelectCommand.Parameters.Add("#Revision", SqlDbType.Int)
dad.SelectCommand.Parameters("#ProjectID").Value = vProjectID
dad.SelectCommand.Parameters("#Revision").Value = vRevision
dad.Fill(dTb) 'Now we have a table with all the elements .
End Using
Conn.Close()
End Using
'Now work with the datatable
'WBS_ID, WBSNo, WBSLevel, ParentID, ParentNo, SortKey, Notes
dTb.DefaultView.Sort = "SortKey ASC"
dTb = dTb.DefaultView.ToTable
Dim vRowCount As Int16
vRowCount = dTb.Rows.Count
Dim vCurRow As Int16 = 0
For x = 0 To vRowCount - 1
If Not IsDBNull(dTb.Rows(x)("ParentID")) Then
Else
dTb.Rows(x)("WBSNo") = "1"
End If
dTb.Rows(x)("Notes") = dTb.Rows(x)("Notes") & vbCrLf & "<<< Old WBS No. = " & dTb.Rows(x)("SortKey")
Next
Renumber the WBS, starting with "1", each child of an element would be numbered with the parent number, plus a period (.) then sequentially starting with 1; each child could have children.

I wrote a recursive sub-routine to update the datatable, then another routine to update the database.
Sub RenumberChildren(vParentID As Int16, vParentWBSNo As String)
Dim ChildCount As Int16 = 0
For x = 0 To dTb.Rows.Count - 1
If Not IsDBNull(dTb.Rows(x)("ParentID")) Then
If dTb.Rows(x)("ParentID") = vParentID Then
ChildCount += 1
dTb.Rows(x)("WBSNo") = vParentWBSNo & "." & ChildCount
RenumberChildren(dTb.Rows(x)("WBS_ID"), dTb.Rows(x)("WBSNo"))
End If
End If
Next
End Sub

Related

Adding new row to unbound datagridview

I have an unbound datagridview. Because of the various things I am doing with the data in the grid I do not want to bind it. The columns are predefined in the settings (Edit Columns) of the datagridview.
I want to create a new row and then populate the grid row with data. I am trying to use the .Add.Rows method but it is failing with
{"Index was out of range. Must be non-negative and less than the size of the collection." & vbCrLf & "Parameter name: index"}
The following SQL retrieves data:
USE CCAP
declare #ScheduleName as varchar(30) = 'Walk-In Center April Wk 1 2019'
Select ShiftName, ScheduleStart, ScheduleEnd, Position, ADP_ID1,
Name1,ADP_ID2, Name2, ADP_ID3, Name3, ADP_ID4, Name4, ADP_ID5,
Name5, ADP_ID6, Name6, ADP_ID7, Name7
from FormattedSchedules
where ScheduleName = #ScheduleName;
and the rowcount is greater than 0 so it is getting results.
I do not understand what index is out of range or why the collection is 0
Code is below:
Tried .Rows.Add(1) and .Rows.Add() and .Rows.Add("")
Dim FSchedCmd As SqlCommand
Dim FSchedSQL As String
Dim FSchedConn As New SqlConnection()
Dim FSchedadapter As New SqlDataAdapter()
Dim i As Integer = 0
Dim rowIndex As Integer
Dim row As DataGridViewRow
AddedNewRow = 1
Dim dsFSched As New DataSet()
FSchedSQL = "Select ShiftName, ScheduleStart, ScheduleEnd, Position, ADP_ID1, Name1, ADP_ID2, Name2, ADP_ID3, Name3, ADP_ID4, Name4, ADP_ID5, Name5, ADP_ID6, Name6, ADP_ID7, Name7 from FormattedSchedules where ScheduleName = #ScheduleName;"
Try
If GlobalVariables.logProd = 1 Then
GlobalVariables.strConnection = "CCAPProdConnectionString"
Else
GlobalVariables.strConnection = "CCAPTestConnectionString"
End If
FSchedConn.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings(GlobalVariables.strConnection).ConnectionString
FSchedConn.Open()
FSchedCmd = New SqlCommand(FSchedSQL, FSchedConn)
FSchedCmd.Parameters.Add("#ScheduleName", SqlDbType.VarChar).Value = cboCreateScheduleName.Text
FSchedadapter.SelectCommand = FSchedCmd
FSchedadapter.Fill(dsFSched)
FSchedadapter.Dispose()
FSchedCmd.Dispose()
FSchedConn.Close()
'dgvCreateSchedule.DataSource = dsFSched.Tables(0)
dgvCreateSchedule.Rows.Clear()
With dgvCreateSchedule
Dim RowNo As Long = 0
'.RowCount = 0
While RowNo <= dsFSched.Tables(0).Rows.Count - 1
.Rows.Add(1)
.Rows(RowNo).Cells(0).Value = dsFSched.Tables(0).Rows(RowNo).Item(0) 'ShiftName
'.Rows(RowNo).Cells(1).Value = dsFSched.Tables(0).Rows(RowNo).Item(1) 'Start Time
.Rows(RowNo).Cells(1).Value = Convert.ToDateTime(dsFSched.Tables(0).Rows(RowNo).Item(1)).TimeOfDay
'.Rows(RowNo).Cells(2).Value = dsFSched.Tables(0).Rows(RowNo).Item(2) 'End Time
.Rows(RowNo).Cells(2).Value = Convert.ToDateTime(dsFSched.Tables(0).Rows(RowNo).Item(2)).TimeOfDay 'End Time
.Rows(RowNo).Cells(3).Value = dsFSched.Tables(0).Rows(RowNo).Item(3) 'Position
.Rows(RowNo).Cells(4).Value = dsFSched.Tables(0).Rows(RowNo).Item(4) 'ADP_ID1
.Rows(RowNo).Cells(5).Value = dsFSched.Tables(0).Rows(RowNo).Item(5) 'Name1
.Rows(RowNo).Cells(6).Value = dsFSched.Tables(0).Rows(RowNo).Item(6) 'ADP_ID2
.Rows(RowNo).Cells(7).Value = dsFSched.Tables(0).Rows(RowNo).Item(7) 'Name2
.Rows(RowNo).Cells(8).Value = dsFSched.Tables(0).Rows(RowNo).Item(8) 'ADP_ID3
.Rows(RowNo).Cells(9).Value = dsFSched.Tables(0).Rows(RowNo).Item(9) 'Name3
.Rows(RowNo).Cells(10).Value = dsFSched.Tables(0).Rows(RowNo).Item(10) 'ADP_ID4
.Rows(RowNo).Cells(11).Value = dsFSched.Tables(0).Rows(RowNo).Item(11) 'Name4
.Rows(RowNo).Cells(12).Value = dsFSched.Tables(0).Rows(RowNo).Item(12) 'ADP_ID5
.Rows(RowNo).Cells(13).Value = dsFSched.Tables(0).Rows(RowNo).Item(13) 'Name5
.Rows(RowNo).Cells(14).Value = dsFSched.Tables(0).Rows(RowNo).Item(14) 'ADP_ID6
.Rows(RowNo).Cells(15).Value = dsFSched.Tables(0).Rows(RowNo).Item(15) 'Name6
.Rows(RowNo).Cells(16).Value = dsFSched.Tables(0).Rows(RowNo).Item(16) 'ADP_ID7
.Rows(RowNo).Cells(17).Value = dsFSched.Tables(0).Rows(RowNo).Item(17) 'Name7
RowNo = RowNo + 1
End While
End With
If dgvCreateSchedule.RowCount > 0 Then
dgvCreateSchedule.Rows(0).Selected = True
dgvCreateSchedule.CurrentCell = dgvCreateSchedule.Rows(0).Cells(0)
'dgvCreateSchedule.FirstDisplayedScrollingRowIndex = dgvCreateSchedule.CurrentRow.Index
End If
Catch ex As Exception
MessageBox.Show("Cannot open FormattedSchedules to load grid")
End Try
AddedNewRow = 0
Error message from line: .Rows.Add(1)
Index was out of range. Must be non-negative and less than the size of the collection." & vbCrLf & "Parameter name: index
This should be the fastest option:
dgvCreateSchedule.Rows.Clear()
For Each xrow As DataRow In TempDataTable.dsFSched.Tables(0).Rows
dgvCreateSchedule.Rows.Add(xrow.ItemArray)
Next
What it does adds all "Cells" along with row.
And when editing cells, I prefer to use
dgvCreateSchedule(y,x).Value = somevalue
'Though it's a little bit strange, as it's column first then row for location hence y then x axis , opposed to usual row then column thats x then y axis
Add it like this, assuming there is the same column count/order
.Rows.Add(dsFSched.Tables(0).Rows(RowNo).ItemArray)
I changed the name of the DGV to DataGridView1 because that is what I happened to have in my test project.
You can use conditional compile statements to chose the correct connection string. Not necessary to keep a Boolean variable somewhere to determine correct string. I know I would forget to change it for the release version.
You did a good job closing and disposing of database objects but if there is an error all that good work will be for naught. A Using...End Using block will accomplish the close, dispose even if there is an error.
Pass the connection string directly to the constructor of the connection and pass the Sql statement and the connection directly to the constructor of the command.
Don't open your connection until the last minute. In the case of a DataAdapter.Fill, the connection is opened and closed for you however, if the adapter finds and open connection it leaves it open. In this case there is no need for an adapter or a DataSet.
I do not see anything wrong with your line .Rows.Add(1). The problem comes on the next line. The index of DataGridView.Rows is an Int32, Integer in vb.net, and you have declared RowNo as Long. Of course you will want to use the code suggested by #CruleD answer.
Private Sub OPCode()
Dim dt As New DataTable
Dim FSchedSQL = "Select ShiftName, ScheduleStart, ScheduleEnd, Position, ADP_ID1, Name1, ADP_ID2, Name2, ADP_ID3, Name3, ADP_ID4, Name4, ADP_ID5, Name5, ADP_ID6, Name6, ADP_ID7, Name7 from FormattedSchedules where ScheduleName = #ScheduleName;"
Try
#If Not DEBUG Then
GlobalVariables.strConnection = "CCAPProdConnectionString"
#Else
GlobalVariables.strConnection = "CCAPTestConnectionString"
#End If
Using FSchedConn As New SqlConnection(ConfigurationManager.ConnectionStrings(GlobalVariables.strConnection).ConnectionString)
Using FSchedCmd As New SqlCommand(FSchedSQL, FSchedConn)
FSchedCmd.Parameters.Add("#ScheduleName", SqlDbType.VarChar).Value = cboCreateScheduleName.Text
FSchedConn.Open()
dt.Load(FSchedCmd.ExecuteReader)
End Using
End Using
DataGridView1.Rows.Clear()
For Each xrow As DataRow In dt.Rows
DataGridView1.Rows.Add(xrow.ItemArray)
Next
If DataGridView1.RowCount > 0 Then
DataGridView1.Rows(0).Selected = True
DataGridView1.CurrentCell = DataGridView1.Rows(0).Cells(0)
End If
Catch ex As Exception
MessageBox.Show("Error loading grid")
End Try
End Sub

convert multiline datatable column to multiline in html table in vb.net

I have added multiline data to "Service Performed" column in datatable, which I am writing to HTML.
Dim row = dt.NewRow()
row("Date") = Display_Date
row("Mileage") = Odometer
For t1 As Integer = 0 To returnData.serviceHistory.displayRecords(d1).text.Count - 1
Text(t1) = returnData.serviceHistory.displayRecords(d1).text(t1).ToString
t_str = t_str + Text(t1) + vbNewLine
row("Service Performed") = t_str
Next
dt.Rows.Add(row)
HTML Part:
Private Function GetBody(ByVal dTable As DataTable) As String
Dim dString As New StringBuilder
dString.Append("<tbody>")
For Each dRow As DataRow In dTable.Rows
dString.Append("<tr align='center' valign='middle'>")
For dCount As Integer = 0 To dTable.Columns.Count - 1
If dCount = 0 Then
dString.AppendFormat("<td>{0}</td>", dRow(dCount).ToShortDateString())
ElseIf dCount = 2 Then
dString.AppendFormat("<td align='left'>{0}</td>", dRow(dCount))
Else
dString.AppendFormat("<td>{0}</td>", dRow(dCount))
End If
Next
dString.Append("</tr>")
Next
dString.Append("</tbody>")
Return dString.ToString()
End Function
I am getting an output for "Service Performed" column as
'Pre-delivery inspection completed Wheel locks installed VIN glass etching vin etched'
HTML
and not in separate line as
'Pre-delivery inspection completed
Wheel locks installed
VIN glass etching vin etched'
What will be the HTML table part of code to display multiline data received from Datatable column in HTML.
You should replace vbNewLine in your code by <br> since you are going to display DataTable values in a html table. Then your string will display in separate lines as you wanted it to.
The only change you need to make is in commented line in code below.
Dim row = dt.NewRow()
row("Date") = Display_Date
row("Mileage") = Odometer
For t1 As Integer = 0 To returnData.serviceHistory.displayRecords(d1).text.Count - 1
Text(t1) = returnData.serviceHistory.displayRecords(d1).text(t1).ToString
t_str = t_str + Text(t1) & "<br>" ''replace vbNewLine with <br>
row("Service Performed") = t_str
Next
dt.Rows.Add(row)

random and shuffle questions vb

i'm puzzled in the logic of shuffling the questions that i'll display from my database.
my current code displays random questions to the textbox but it also display empty and duplicate entries.
Dim r As MySqlDataReader
Dim i As Integer = 0
Dim temp() As Integer = {}
Dim txtQ() As TextBox = {txtQ1, txtQ2, txtQ3, txtQ4, txtQ5, txtQ6, txtQ7, txtQ8, txtQ9, txtQ10}
Dim cbA() As CheckedListBox = {cbA1, cbA2, cbA3, cbA4, cbA5, cbA6, cbA7, cbA8, cbA9, cbA10}
con.Open()
cmd = New MySqlCommand("select * from tbexam", con)
r = cmd.ExecuteReader
While r.Read
If i <= 9 Then
Randomize()
Dim j As Integer = CInt(Int(9 * Rnd()))
txtQ(j).Text = r.GetString("exam_question")
cbA(j).Items.Clear()
cbA(j).Items.Add("a) " & r.GetString("exam_ans_a"))
cbA(j).Items.Add("b) " & r.GetString("exam_ans_b"))
cbA(j).Items.Add("c) " & r.GetString("exam_ans_c"))
cbA(j).Items.Add("d) " & r.GetString("exam_ans_d"))
i = i + 1
End If
End While
When you place a random number in j, it is (very nearly) a random number between 0 and 9. This is equivalent to rolling a ten-sided dice. What do you think the chances are that if you were to roll it ten times you would get exactly one of each of the values 0 to 9? Pretty low. What you will actually get is something like: 2, 0, 8, 2, 5, 1, 7, 6, 1, 4. This sequence contains duplicates of 2 and 1 and the values 3, and 9 do not appear. This is where your duplicates and gaps come from.
One option you could try is to fill the array sequentially and then shuffle it.
Dim r As MySqlDataReader
Dim i As Integer = 0
Dim temp() As Integer = {}
Dim txtQ() As TextBox = {txtQ1, txtQ2, txtQ3, txtQ4, txtQ5, txtQ6, txtQ7, txtQ8, txtQ9, txtQ10}
Dim cbA() As CheckedListBox = {cbA1, cbA2, cbA3, cbA4, cbA5, cbA6, cbA7, cbA8, cbA9, cbA10}
con.Open()
cmd = New MySqlCommand("select * from tbexam", con)
r = cmd.ExecuteReader
' Read the Q&As into the arrays in the order they appear in the DB
While r.Read
If i <= 9 Then
txtQ(i).Text = r.GetString("exam_question")
cbA(i).Items.Clear()
cbA(i).Items.Add("a) " & r.GetString("exam_ans_a"))
cbA(i).Items.Add("b) " & r.GetString("exam_ans_b"))
cbA(i).Items.Add("c) " & r.GetString("exam_ans_c"))
cbA(i).Items.Add("d) " & r.GetString("exam_ans_d"))
i = i + 1
End If
End While
' Re-order the arrays by swapping each element with another, randomly selected element.
' Start with i at the count of the elements read in the last loop and work down.
Dim n as Integer = i - 1
While i > 0
Dim j As Integer = CInt(Int(n * Rnd()))
i = i - 1
' Swap elements i and j of the arrays
Dim tmpQ As TextBox = txtQ(i)
txtQ(i) = txtQ(j)
txtQ(j) = tmpQ
Dim tmpA() As CheckedListBox = cbA(i)
cbA(i) = cbA(j)
cbA(j) = tmpA
End While
This could be simplified and abstracted but you get the idea.
It is hard to avoid duplicate entry using random number generation, but you can avoid empty entries. You get empty entries because you generates random number and fetch question with that id, and unfortunately that id is not available in database always. SO first, fetch all the ids from database in an array and generate random number from 0 to array length. and select id value of array key.

Removing Items in a List While Iterating Through It with For Each Loop

I have a list named NeededList I need to check each item in this list to see if it exists in my database. If it does exist in the database I need to remove it from the list. But I can't change the list while I'm iterating through it. How can I make this work?
Here is my code so far:
For Each Needed In NeededList
Dim Ticker = Needed.Split("-")(0).Trim()
Dim Year = Needed.Split("-")(1).Trim()
Dim Period = Needed.Split("-")(2).Trim()
Dim Table = Needed.Split("-")(3).Trim()
Dim dr As OleDbDataReader
Dim cmd2 As New OleDb.OleDbCommand("SELECT * FROM " & Table & " WHERE Ticker = ? AND [Year] = ? AND Period = ?", con)
cmd2.Parameters.AddWithValue("?", Ticker)
cmd2.Parameters.AddWithValue("?", Year)
cmd2.Parameters.AddWithValue("?", Period)
dr = cmd2.ExecuteReader
If dr.HasRows Then
NeededList.Remove(Needed)
End If
Next
No you can't do that using a for each, but you can do that using the old fashioned for .. loop.
The trick is to start from the end and looping backwards.
For x = NeededList.Count - 1 to 0 Step -1
' Get the element to evaluate....
Dim Needed = NeededList(x)
.....
If dr.HasRows Then
NeededList.RemoveAt(x)
End If
Next
You need to approach the loop in this way because you don't risk to skip elements because the current one has been deleted.
For example, suppose that you remove the fourth element in the collection, after that, the fifth element becomes the fourth. But then the indexer goes up to 5. In this way, the previous fifth element (now in fourth position) is never evaluated. Of course you could try to change the value of the indexer but this ends always in bad code and bugs waiting to happen.
Go for safe and make a copy with ToList():
For Each Needed In NeededList.ToList()
Dim Ticker = Needed.Split("-")(0).Trim()
...
If dr.HasRows Then
NeededList.Remove(Needed)
End If
Next
You can use a For loop iterating through every index with Step -1.
For i as Integer = NeededList.Count - 1 to 0 Step -1
Dim Needed = NeededList(i)
'this is a copy of your code
Dim Ticker = Needed.Split("-")(0).Trim()
Dim Year = Needed.Split("-")(1).Trim()
Dim Period = Needed.Split("-")(2).Trim()
Dim Table = Needed.Split("-")(3).Trim()
Dim dr As OleDbDataReader
Dim cmd2 As New OleDb.OleDbCommand("SELECT * FROM " & Table & " WHERE Ticker = ? AND [Year] = ? AND Period = ?", con)
cmd2.Parameters.AddWithValue("?", Ticker)
cmd2.Parameters.AddWithValue("?", Year)
cmd2.Parameters.AddWithValue("?", Period)
dr = cmd2.ExecuteReader
'MODIFIED CODE
If dr.HasRows Then NeededList.RemoveAt(i)
Next i
The contents of an array (or anything else you can fast enumerate with For Each can not be modified with a For Each loop. You need to use a simple For loop and iterate through every index.
Hint: Because you'll be deleting indexes, I suggest starting at the last index and work your way toward the first index so you don't skip over one every time you delete one.
You can also invert the order of the list's elements and still use For Each using the IEnumerable Cast and Reverse extensions.
Simple example using a List(Of String):
For Each Needed In NeededList.Cast(Of List(Of String)).Reverse()
If dr.HasRows Then
NeededList.Remove(Needed)
End If
Next
How about this (no iteration needed):
NeededList = (NeededList.Where(Function(Needed) IsNeeded(Needed)).ToList
Function IsNeeded(Needed As ...) As Boolean
...
Return Not dr.HasRows
End Function
No you can not remove from a List that you are working on e.g.
For Each Str As String In listOfStrings
If Str.Equals("Pat") Then
Dim index = listOfStrings.IndexOf(Str)
listOfStrings .RemoveAt(index)
End If
Next
But this way will work make a copy of your list and delete from it e.g.
For Each Str As String In listOfStrings
If Str.Equals("Pat") Then
Dim index = listOfStringsCopy.IndexOf(Str)
listOfStringsCopy.RemoveAt(index)
End If
Next

Adding two column values to listbox in vb.net

I have a table named users which has the following columns in it
User_id,user_name,user_pwd,First_Name,Middle_Name,Last_Name and user_type.
I have dataset named dst and created a table called user in the dataset. Now I want to populate listbox with user_Name, First_Name, Last_name of each and every row in the table user.
I am able to add one column value at a time but not getting how to add multiple column values of each row to listbox
Dim dt As DataTable = Dst.Tables("user")
For Each row As DataRow In dt.Rows
lstUsers.Items.Add(row("User_Name"))
Next
Above code works perfectly but I also want to add First_name as well as last_name to the list box at the same time.
Use same approach as you have, but put all values you want in one string.
Dim dt As DataTable = Dst.Tables("user")
For Each row As DataRow In dt.Rows
Dim sItemTemp as String
sItemTemp = String.Format("{0},{1},{2}", row("User_Name"), row("First_Name"), row("Last_Name"))
lstUsers.Items.Add(sItemTemp)
Next
String.Format() function will call .ToString() on all parameters.
In this case if row(ColumnName) is NULL value then .ToString() return just empty string
You have 2 choices:
Using the ListBox:
To use the ListBox, set the font to one that is fixed width like courier new (so that the columns line up), and add the items like this:
For Each row As DataRow In dt.Rows
lstUsers.Items.Add(RPAD(row("User_Name"),16) & RPAD(row("First_Name"),16) & RPAD(row("Last_Name"),16))
Next
The RPAD function is defined like this:
Function RPAD(a As Object, LENGTH As Object) As String
Dim X As Object
X = Len(a)
If (X >= LENGTH) Then
RPAD = a : Exit Function
End If
RPAD = a & Space(LENGTH - X)
End Function
Adjust the LENGTH argument as desired in your case. Add one more for at least one space. This solution is less than ideal because you have to hard-code the column widths.
Use a DataGridView control instead of a ListBox. This is really the best option, and if you need, you can even have it behave like a ListBox by setting the option to select the full row and setting CellBorderStyle to SingleHorizontal. Define the columns in the designer, but no need to set the widths - the columns can auto-size, and I set that option in the code below. if you still prefer to set the widths, comment out the AutoSizeColumnsMode line.
The code to set up the grid and add the rows goes like this:
g.Rows.Clear() ' some of the below options are also cleared, so we set them again
g.AutoSizeColumnsMode = DataGridViewAutoSizeColumnMode.AllCells
g.CellBorderStyle = DataGridViewCellBorderStyle.SingleHorizontal
g.SelectionMode = DataGridViewSelectionMode.FullRowSelect
g.AllowUserToAddRows = False
g.AllowUserToDeleteRows = False
g.AllowUserToOrderColumns = True
For Each row As DataRow In dt.Rows
g.Rows.Add(row("User_Name"), row("First_Name"), row("Last_Name"))
Next
You might solved your problem by now but other users like me might have issue with it.
Above answers given worked for me even but I found a same answer in a simple way according to what I want..
cmd = New SqlCommand("select User_Name, First_Name, Last_Name from User")
Dim dr As SqlDataReader = cmd.ExecuteReader(YourConnectionString)
If dr.HasRows Then
Do While dr.Read
lst.Items.Add(dr.Item(0).ToString & " " & dr.Item(1).ToString & " " & dr.Item(2).ToString)
Loop
End If
This worked for me, maybe wrong way but I found it simple :)
May I suggest you use a ListView control instead of Listbox?
If you make the switch, here's a sample subroutine you could use to fill it up with the data you said you want. Adapt it the way you like; there's much room for improvement but you get the general idea:
Public Sub FillUserListView(lstUsers As ListView, Dst As DataSet)
Dim columnsWanted As List(Of String) = New List(Of String)({"User_Name", "First_Name", "Last_Name"})
Dim dt As DataTable = Dst.Tables("user")
Dim columns As Integer = 0
Dim totalColumns = 0
Dim rows As Integer = dt.Rows.Count
'Set the column titles
For Each column As DataColumn In dt.Columns
If columnsWanted.Contains(column.ColumnName) Then
lstUsers.Columns.Add(column.ColumnName)
columns = columns + 1
End If
totalColumns = totalColumns + 1
Next
Dim rowObjects(columns - 1) As ListViewItem
Dim actualColumn As Integer = 0
'Load up the rows of actual data into the ListView
For row = 0 To rows - 1
For column = 0 To totalColumns - 1
If columnsWanted.Contains(dt.Columns(column).ColumnName) Then
If actualColumn = 0 Then
rowObjects(row) = New ListViewItem()
rowObjects(row).SubItems(actualColumn).Text = dt.Rows(row).Item(actualColumn)
Else
rowObjects(row).SubItems.Add(dt.Rows(row).Item(actualColumn))
End If
lstUsers.Columns.Item(actualColumn).Width = -2 'Set auto-width
actualColumn = actualColumn + 1
End If
Next
lstUsers.Items.Add(rowObjects(row))
Next
lstUsers.View = View.Details 'Causes each item to appear on a separate line arranged in columns
End Sub