Deleting items in listview if data already exists - vb.net

i'am populating my listview and when i click the command button the data will be saved to database but if a data already exists in the database the data will be removed from my listview. my problem is that when the data already exists yes it removes the data but it always leave 1 data in my listview. for example i populate my list with 10 data that already exist in database and when i press the command button since its already in the database it will delete the 10 data in my listview what happens is it leaves the last data in the listview
Dim ListOfExistingItem As List(Of Integer) = New List(Of Integer)
Try
locconn.Open()
For x = 0 To ListView2.Items.Count - 1
Dim a As String = ListView2.Items.Item(x).Text
a = ListView2.Items.Item(x).Text
Dim command As New SqlCommand
Dim TMP_SQL_VAL As String = "select count([Check-Out]) from tbl_list1 where barcode = '" + a + "'"
command = New SqlCommand(TMP_SQL_VAL, locconn)
Dim READER As SqlDataReader
READER = command.ExecuteReader()
READER.Read()
If READER(0) = 0 Then
MsgBox("Barcode: " & a & "is still Inside", MsgBoxStyle.Exclamation)
TextBox4.Text = Nothing
ListOfExistingItem.Add(x)
READER.Close()
End If
READER.Close()
Next
If Not IsNothing(ListOfExistingItem) Then
For Each x As Integer In ListOfExistingItem
If Not x >= ListView2.Items.Count - 1 Then
ListView2.Items.RemoveAt(x)
End If
Next
End If

I think your problem is a little more complex than an off-by-1 error.
When you loop through ListOfExistingItem, which should contains the indexes of items to be removed, you are removing items from ListView2.
The problem with this is that by removing an item from the list, you are changing the position of all items after it.
For example, take the list { a, b, c }. The index of 'a' is 0, 'b' is 1, and 'c' is 2.
Now, if you were to say list.RemoveAt(1) then it would remove 'b'. This will then cause the index of 'c' to change to 1 instead of two. Then when you go and try to remove 'c', it wont be in the same place.
For an quick fix, try adding 'ListOfExistingItem.Reverse' before the last 'for' loop:
Call ListOfExistingItem.Reverse()
For Each x As Integer In ListOfExistingItem
If Not x >= ListView2.Items.Count - 1 Then
ListView2.Items.RemoveAt(x)
End If
Next
This way, you will start with the last item in the list and work your way backwards, which should avoid the problem.

Related

Adding all elements of an list in a dynamic table vb.net

Protected Sub createTable()
Try
Dim listB As New ArrayList()
Dim dt As New DataTable
Dim info As SessioneUtente = Session(SessionVariables.InformazioniUtente)
Dim id As String = info.getIdDisciplinaDefault.ToString
dt = operations.G_Number(id)
If dt.Rows.Count = 0 Then
notifica.Text = "There is no number for this id"
Else
For Each row In dt.Rows
list.Add(row(0))
listB.Add(row(0))
Next
listB.Add(23)
listB.Add(24)
listB.Add(25)
Dim cell1 As New TableCell
Dim cell2 As New TableCell
Dim Nr As New Label
Dim Icon As New Label
Dim row1 As New TableRow
Dim row2 As New TableRow
For Each item In listB
If list.Contains(item) Then
Nr.Text = item
Icon.Text = "<img = src='../Images/Icon1.png' />"
cell1.Controls.Add(Nr)
cell2.Controls.Add(Icon)
row1.Cells.Add(cell1)
row2.Cells.Add(cell2)
Else
Nr.Text = item & vbLf
Icon.Text = "<img = src='../Images/Icon2.png' />"
cell1.Controls.Add(Nr)
cell2.Controls.Add(Icon)
row1.Cells.Add(cell1)
row2.Cells.Add(cell2)
End If
Next
tabel.Rows.Add(row1)
tabel.Rows.Add(row2)
notifica.Visible = False
End If
Catch ex As Exception
Dim log As New Log
log.writeLog("default", ex)
End Try
End Sub
I'm dynamically populating a table via VB.NET using an arraylist but the table gets only the last element of the list. The list takes some elements from database and the other I add by myself. I need some help about displaying all the element of the list in the dynamic table.
Thank you in advance!
I would try moving my variables that I was dimensioning inside of my foreach loop. It appears to me that you are overwriting them each time. You seem to be overwriting the same memory location on each loop. Moving them inside of the loop should create a new memory location for each item in the list. I am guessing that you are seeing the correct number of rows but they all have the same values which happen to be the last item in the list. This is because it is being overwritten and there are only pointers to that memory location being added on each loop. You also need to move where you are adding it into the table inside of the loop for each iteration because right now you are only adding the last thing you set the row to and when you move those variables into the loop it is going to throw you an error. You want to add each row into the table while it is in scope with the current data.

System.InvalidCastException Error on Specific Database Column

So I am currently trying to read values from an access database and write them to an array of labels in VB.NET. This is for a little quiz program I am making where the previous scores they got in the 14 categories are written to the screen. The issue I am having is when writing to Label7 (column 20 in the database) I get the error 'specified cast is not valid'. I have checked my txt file and database thoroughly to see what is wrong with this specific value and I cannot see a difference. It is still written as a 32 bit integer like all the others, for which the code has no issues.
Dim LabelArray() As Control = {Label1, Label2, Label3, Label4, Label5, Label6, Label7, Label8, Label9, Label10, Label11, Label12, Label13, Label14}
Dim x As Integer = 2
'starting at the the 3rd column in the database
Dim QArray(13) As String 'reading names of the columns from a txt file into the array
FileOpen(1, Application.StartupPath & "\sqlscores.txt", OpenMode.Input) 'load files
Dim j As Integer = 0
Do While Not EOF(1)
QArray(j) = LineInput(1) 'input into array
j = j + 1
Loop
FileClose(1)
Dim tbl As New DataTable
Dim conn1 = MyConnection2() 'connects to microsoft access database
Dim temp As String
For i = 0 To 13 'for each item in the array
Dim command = New OleDbCommand("Select * From Users Where Username='" & usernames & "' and " & QArray(i) & " >= 0", conn) 'look for that column in the database where their username and score is more than 0
Dim reader = command.ExecuteReader()
While reader.Read()
temp = (reader.GetInt32(x)).ToString 'read value and convert to string
LabelArray(i).Text = temp 'assign temp to label text
x = x + 3 'increment by 3 as correct column is in every third column
End While
Next i
Below is a screenshot of the database (the specific column) that is causing the issue.
The first field is the section that is playing up
As you can see, it has the same properties as a section that does work compared to a section that does
I have tried deleting the column and adding it again, which makes no difference. I have also checked the label (and re-added it) in VB to see if that was the issue, which it was not. It appears to think that the value in that column, which is just currently the 32 bit integer "4" cannot be converted to a string. I am only interested in the practice scores in the db which can be seen in the column names.
Am I missing something obvious?

Highlight DataGridViewRows based on value comparison with other rows

I have a Part class with the fields list in the code below. I have a DataGridView control, which I am filtering with the Advanced DGV (ADGV) DLL from NUGET. I must include the ADGV in my winform. I currently have a DataGridView, a search box on the form, and a button to run the following function. I need to go through all of the visible rows, collect a unique list of part numbers with their most recent revisions, and then color the rows in DataGridView which are out of date by checking the part number and rev on each row against the mostuptodate list. For 45,000 entries displayed in DataGridView, this take ~17 secs. For ~50 entries, it take ~1.2 seconds. This is extremely inefficient, but I can't see a way to cut the time down.
Sub highlightOutdatedParts()
'Purpose: use the results in the datagridview control, find the most recent revision of each part, and
' highlight all outdated parts relative to their respective most recent revisions
'SORT BY PART NUMBER AND THEN BY REV
If resultsGrid.ColumnCount = 0 Or resultsGrid.RowCount = 0 Then Exit Sub
Dim stopwatch As New Stopwatch
stopwatch.Start()
resultsGrid.Sort(resultsGrid.Columns("PartNumber"), ListSortDirection.Ascending)
Dim iBag As New ConcurrentBag(Of Part)
Dim sortedList As Generic.List(Of Part)
For Each row As DataGridViewRow In resultsGrid.Rows
If row.Visible = True Then
Dim iPart As New Part()
Try
iPart.Row = row.Cells(0).Value
iPart.Workbook = CStr(row.Cells(1).Value)
iPart.Worksheet = CStr(row.Cells(2).Value)
iPart.Product = CStr(row.Cells(3).Value)
iPart.PartNumber = CStr(row.Cells(4).Value)
iPart.ItemNo = CStr(row.Cells(5).Value)
iPart.Rev = CStr(row.Cells(6).Value)
iPart.Description = CStr(row.Cells(7).Value)
iPart.Units = CStr(row.Cells(8).Value)
iPart.Type = CStr(row.Cells(9).Value)
iPart.PurchCtgy = CStr(row.Cells(10).Value)
iPart.Qty = CDbl(row.Cells(11).Value)
iPart.TtlPerProd = CDbl(row.Cells(12).Value)
iPart.Hierarchy = CStr(row.Cells(13).Value)
iBag.Add(iPart)
Catch ice As InvalidCastException
Catch nre As NullReferenceException
End Try
End If
Next
sortedList = (From c In iBag Order By c.PartNumber, c.Rev).ToList() ' sort and convert to list
Dim mostUTDRevList As New Generic.List(Of Part) ' list of most up to date parts, by Rev letter
For sl As Integer = sortedList.Count - 1 To 0 Step -1 'start at end of list and work to beginning
Dim query = From entry In mostUTDRevList ' check if part number already exists in most up to date list
Where entry.PartNumber = sortedList(sl).PartNumber
Select entry
If query.Count = 0 Then ' if this part does not already exist in the list, add.
mostUTDRevList.Add(sortedList(sl))
End If
Next
'HIGHLIGHT DATAGRIDVIEW ROWS WHERE PART NUMBERS ARE OUT OF DATE
For Each row As DataGridViewRow In resultsGrid.Rows
' if that part with that Rev does not exist in the list, it must be out of date
Try
Dim rowPN As String = CStr(row.Cells(4).Value).ToUpper ' get part number
Dim rowR As String = CStr(row.Cells(6).Value).ToUpper ' get Rev
Dim query = From entry In mostUTDRevList ' check if that part number with that Rev is in the list.
Where entry.PartNumber.ToUpper.Equals(rowPN) AndAlso
entry.Rev.ToUpper.Equals(rowR)
Select entry
If query.Count = 0 Then ' if the part is out of date highlight its' row
row.DefaultCellStyle.BackColor = Color.Chocolate
End If
Catch ex As NullReferenceException
Catch ice As InvalidCastException
End Try
Next
resultsGrid.Select()
stopwatch.Stop()
If Not BackgroundWorker1.IsBusy() Then timertextbox.Text = stopwatch.Elapsed.TotalSeconds.ToString & " secs"
MessageBox.Show("Highlighting completed successfully.")
End Sub
It is almost always faster to work with the data than the control. The control is simply the means to present a view of the data (in a grid) to the users. Working with the data from there requires too much converting to be effieicent. Then, use the DGV events to highlight the rows
Its hard to tell all the details of what you are doing, but it looks like you are comparing the data to itself (as opposed to some concrete table where the lastest revision codes are defined). Nor is it clear why the datasources are collections, ConcurrentBags etc. The key would be to use collections optimized for the job.
To demonstrate, I have a table with 75,000 rows; the product codes are randomly selected from a pool of 25,000 and a revision code is a random integer (1-9). After the DGV datasource is built (a DataTable) a LookUp is created from the ProductCode-Revision pair. This is done once and once only:
' form level declaration
Private PRCodes As ILookup(Of String, Int32)
' go thru table
' group by the product code
' create an anon Name-Value object for each,
' storing the code and highest rev number
' convert result to a LookUp
PRCodes = dtSample.AsEnumerable.
GroupBy(Function(g) g.Item("ProductCode"),
Function(key, values) New With {.Name = key.ToString(), .Value = values.
Max(Of Int32)(Function(j) j.Field(Of Int32)("RevCode"))
}).
ToLookup(Of String, Int32)(Function(k) k.Name, Function(v) v.Value)
Elapsed time via stopwatch: 81 milliseconds to create the collection of 23731 items. The code uses an anonymous type to store a Max Revision code for each product code. A concrete class could also be used. If you're worried about mixed casing, use .ToLowerInvariant() when creating the LookUp (not ToUpper -- see What's Wrong With Turkey?) and again later when looking up the max rev.
Then rather than looping thru the DGV rows use the RowPrePaint event:
If e.RowIndex = -1 Then Return
If dgv1.Rows(e.RowIndex).IsNewRow Then Return
' .ToLowerInvariant() if the casing can vary row to row
Dim pc = dgv1.Rows(e.RowIndex).Cells("ProductCode").Value.ToString()
Dim rv = Convert.ToInt32(dgv1.Rows(e.RowIndex).Cells("RevCode").Value)
Dim item = PRCodes(pc)(0)
If item > rv Then
dgv1.Rows(e.RowIndex).DefaultCellStyle.BackColor = Color.MistyRose
End If
Notes
It takes some time to create the DataSource, but 75,000 rows is a lot to throw at a user
The time to create the LookUp is minimal - barely measurable
There is no noticeable wait in displaying them because a) the LookUp is made for this sort of thing, b) rows are done as needed when they are displayed. Row # 19,999 may never be processed if the user never scrolls that far.
This is all geared to just color a row. If you needed to save the Current/NotCurrent state for each row, add a Boolean column to the DataTable and loop on that. The column can be invisible if to hide it from the user.
The random data results in 47,000 out of date RevCodes. Processing 75k rows in the DataTable to set the flag takes 591 milliseconds. You would want to do this before you set the DataTable as the DataSource to prevent changes to the data resulting in various events in the control.
In general, the time to harvest the max RevCode flag and even tag the out of date rows is a trivial increment to creating the datasource.
The Result:
The data view is sorted by ProductCode so that the coloring of lower RevCodes is apparent.
We surely cant grok all the details and constraints of the system from a small snippet - even the data types and original datasource are a guess for us. However, this should provide some help with better look-up methods, and the concept of working with the data rather than the user's view.
One thing is the revision code - yours is treating them as a string. If this is alphanumeric, it may well not compare correctly - "9" sorts/compares higher than "834" or "1JW".
See also:
Lookup(Of TKey, TElement) Class
Anonymous Types
The solution was spurred in part by #Plutonix.
Sub highlightOutdatedParts()
If resultsGrid.ColumnCount = 0 Or resultsGrid.RowCount = 0 Then Exit Sub
Dim stopwatch As New Stopwatch
stopwatch.Start()
resultsGrid.DataSource.DefaultView.Sort = "PartNumber ASC, Rev DESC"
resultsGrid.Update()
'HIGHLIGHT DATAGRIDVIEW ROWS WHERE PART NUMBERS ARE OUT OF DATE
Dim irow As Long = 0
Do While irow <= resultsGrid.RowCount - 2
' if that part with that Rev does not exist in the list, it must be out of date
Dim utdPN As String = resultsGrid.Rows(irow).Cells(4).Value.ToString().ToUpper()
Dim utdRev As String = resultsGrid.Rows(irow).Cells(6).Value.ToString().ToUpper()
Dim iirow As Long = irow + 1
'If iirow > resultsGrid.RowCount - 1 Then Exit Do
Dim activePN As String = Nothing
Dim activeRev As String = Nothing
Try
activePN = resultsGrid.Rows(iirow).Cells(4).Value.ToString().ToUpper()
activeRev = resultsGrid.Rows(iirow).Cells(6).Value.ToString().ToUpper()
Catch ex As NullReferenceException
End Try
Do While activePN = utdPN
If iirow > resultsGrid.RowCount - 1 Then Exit Do
If activeRev <> utdRev Then
resultsGrid.Rows(iirow).DefaultCellStyle.BackColor = Color.Chocolate
End If
iirow += 1
Try
activePN = resultsGrid.Rows(iirow).Cells(4).Value.ToString().ToUpper()
activeRev = resultsGrid.Rows(iirow).Cells(6).Value.ToString().ToUpper()
Catch nre As NullReferenceException
Catch aoore As ArgumentOutOfRangeException
End Try
Loop
irow = iirow
Loop
resultsGrid.Select()
stopwatch.Stop()
If Not BackgroundWorker1.IsBusy() Then
timertextbox.Text = stopwatch.Elapsed.TotalSeconds.ToString & " secs"
resultcounttextbox.Text = resultsGrid.RowCount - 1 & " results"
End If
MessageBox.Show("Highlighting completed successfully.")
End Sub

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