I want to ask if anyone knows this why this error occurs? So there are 2 forms. The first calculation form there is no error and this is the second calculation form which produces the error, after searching here and there masi not yet enlightenment, maybe someone can help?
THIS SCREENSHOT OF ERROR
this full source code
Public Class FrmHitung2
Private Sub FrmHitung2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim dt As DataTable = openDT("SELECT * FROM tb_rel_alternatif2 WHERE kode_crips NOT IN (SELECT kode_crips FROM tb_crips2)")
If dt.Rows.Count > 0 Then
msgError("Anda belum mengatur nilai untuk setiap alternatif, silahkan atur di menu Nilai Bobot")
BtnCetak.Enabled = False
Else
Dgv1.AllowUserToAddRows = False
Dgv1.AllowUserToDeleteRows = False
Dgv1.ReadOnly = True
Dgv1.AutoGenerateColumns = False
awal()
End If
End Sub
Sub awal()
Dgv1.Columns.Clear()
Dgv1.Rows.Clear()
Dgv1.Columns.Add("nim", "Kode")
Dgv1.Columns("nim").ReadOnly = True
Dgv1.Columns.Add("nama_mahasiswa", "Nama")
Dgv1.Columns("nama_mahasiswa").ReadOnly = True
dr = openDR("SELECT * FROM tb_alternatif2 ORDER BY nim")
While dr.Read()
Dgv1.Rows.Add(dr(0), dr(1))
End While
dr = openDR("SELECT kode_kriteria, atribut FROM tb_kriteria2 ORDER BY kode_kriteria")
While dr.Read()
Dgv1.Columns.Add(dr(0), dr(0))
Dgv1.Columns(dr(0).ToString()).ToolTipText = dr(1).ToString()
End While
For a = 0 To Dgv1.Rows.Count - 1
dr = openDR("SELECT c.nama_crips FROM tb_rel_alternatif2 r " &
" LEFT JOIN tb_crips2 c ON c.kode_crips = r.kode_crips " &
" WHERE nim='" & Dgv1.Rows(a).Cells(0).Value & "' ORDER BY r.kode_kriteria")
Dim b As Integer = 2
While dr.Read
Dgv1.Rows(a).Cells(b).Value = dr(0)
b = b + 1
End While
Next
Dgv1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells
BtnCetak.Enabled = False
End Sub
Function get_col_max(ByVal dgv As DataGridView, ByVal col_name As String) As Double
Dim max As Double = 0
If dgv.Rows.Count > 0 Then max = Val(dgv.Rows(0).Cells(col_name).Value)
For Each row As DataGridViewRow In dgv.Rows
If Val(row.Cells(col_name).Value) > max Then
max = Val(row.Cells(col_name).Value)
End If
Next
get_col_max = max
End Function
Function get_col_min(ByVal dgv As DataGridView, ByVal col_name As String) As Double
Dim min As Double = 0
If dgv.Rows.Count > 0 Then min = Val(dgv.Rows(0).Cells(col_name).Value)
For Each row As DataGridViewRow In dgv.Rows
If Val(row.Cells(col_name).Value) < min Then
min = Val(row.Cells(col_name).Value)
End If
Next
get_col_min = min
End Function
Private Sub BtnHitung_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnHitung.Click
Dim a, b As Integer
awal()
Dgv1.copyTo(Dgv2)
For a = 0 To Dgv2.Rows.Count - 1
dr = openDR("SELECT c.nilai FROM tb_rel_alternatif2 r " &
" LEFT JOIN tb_crips2 c ON c.kode_crips = r.kode_crips " &
" WHERE nim='" & Dgv2.Rows(a).Cells(0).Value & "' ORDER BY r.kode_kriteria")
b = 2
While dr.Read
Dgv2.Rows(a).Cells(b).Value = dr(0)
b = b + 1
End While
Next
Dgv2.copyTo(Dgv3)
For Each row As DataGridViewRow In Dgv2.Rows
For b = 2 To Dgv2.Columns.Count - 1
Dim v = row.Cells(b).Value
If Dgv2.Columns(b).ToolTipText = "benefit" Then
Dgv3.Rows(row.Index).Cells(b).Value = v / get_col_max(Dgv2, Dgv2.Columns(b).Name)
Else
Dgv3.Rows(row.Index).Cells(b).Value = get_col_min(Dgv2, Dgv2.Columns(b).Name) / v
End If
Next
Next
dr = openDR("SELECT kode_kriteria, bobot FROM tb_kriteria2 ORDER BY kode_kriteria")
While dr.Read()
Dgv3.Columns(dr(0).ToString()).ToolTipText = dr(1).ToString()
End While
Dgv3.copyTo(Dgv4)
For Each row As DataGridViewRow In Dgv3.Rows
For b = 2 To Dgv3.Columns.Count - 1
Dim v = row.Cells(b).Value
Dgv4.Rows(row.Index).Cells(b).Value = v * Val(Dgv3.Columns(b).ToolTipText)
Next
Next
Dgv4.Columns.Add("total", "Total")
For Each row As DataGridViewRow In Dgv4.Rows
For b = 2 To Dgv2.Columns.Count - 1
row.Cells("total").Value = row.Cells("total").Value + row.Cells(b).Value
Next
Next
Dgv4.copyTo(Dgv5)
Dgv5.Sort(Dgv5.Columns("total"), System.ComponentModel.ListSortDirection.Descending)
For Each row As DataGridViewRow In Dgv5.Rows
execute("UPDATE tb_alternatif2 SET total=#0, rank=#1 WHERE nim=#2", row.Cells("total").Value, row.Index + 1, row.Cells("nim").Value)
Next
TabControl1.SelectedTab = TabRangking
BtnCetak.Enabled = True
End Sub
Private Sub BtnCetak_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnCetak.Click
LapRangking.ShowAsChild(Me.MdiParent)
End Sub
Private Sub BtnKeluar_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnKeluar.Click
Me.Close()
End Sub
End Class
Why are your using dr.Read() at one place and dr.Read in another. Underlined in RED. Maybe the DataReader is not populated yet!, It should be dr.Read()
That error occurs when you try to access an array or other collection with an index that doesn't exist. Note that indexing starts at 0 all the way to Count - 1.
From you screenshot I can see the error occurs at this line Dgv1.Rows(a).Cells(b).Value = dr(0). a is defined in a For loop this way, For a = 0 To Dgv1.Rows.Count - 1 so it is unlikely that is the culprit.
You may want to check the value of b which you have started with a value of 2. If you're trying to access the second item in the collection, you will have to change that line to read...
Dim b As Integer = 1 ' If you wanted to start from the 2nd cell.
While dr.Read
Dgv1.Rows(a).Cells(b).Value = dr(0)
b = b + 1
End While
b is likely growing past the number of cells you have and causing that problem.
Note: I have changed the definition of b to start at 1
Update 2
After looking at your code again, I'm seeing something that I seem to have missed when looking at line that caused the error. You are defining b as, Dim b As Integer = 2 ' I recommended changing that to 1 and using it to access the columns in your dataset/reader. But when I look at your queries, something else reveals itself. The 1st one in the awal() method is
SELECT * FROM tb_alternatif2 ORDER BY nim
which returns an ordered set with an unknown (to me anyway) number of rows and columns. You are then looping through adding the 1st and 2nd columns of the data reader to rows of what I assume is a data grid view. After that, you make a call to another query
SELECT kode_kriteria, atribut FROM tb_kriteria2 ORDER BY kode_kriteria
which returns an ordered set with 2 columns that you add as columns to the data grid view. Next you have the query
SELECT c.nama_crips FROM tb_rel_alternatif2 r --... truncated
which returns one column which is when you are defining b. Somewhere between the number of columns you are creating and then addressing them with b, you are probably hitting an off by one error. Or more than off by one. Assuming the 2nd query creates for you 10 columns and the third query returns 15 rows, you will quickly run out of columns to address using .Cells(b).Value in your code.
It is unclear to me what you are trying to do with this, but I would recommend trying to define your query again and binding once to the data grid. As an aside: I would also recommend using parameters for constructing your queries because the way you have done isn't too secure... SQL injection and all that.
Related
I am trying to add a search function to a DataGridView in vb.net using this code
For i As Integer = 0 To ContactsList.RowCount - 1
For j As Integer = 0 To ContactsList.ColumnCount - 1
If ContactsList.Rows(i).Cells(j).Value.ToString.ToLower.Trim = ContactsListSearch.Text.ToLower.Trim Then
MsgBox("Item found " + i.ToString)
ContactsList.Rows(i).Visible = True
Else
ContactsList.Rows(i).Visible = False
End If
Next
Next
I'm seeing the MsgBox show when the value matches, but the rows are not showing, it just hides all rows
Another possible option is to load data into a DataTable, create a BindingSource, set the BindingSource DataSource property to the DataTable. Set the DataGridView DataSource property to the BindingSource.
The following example works against a column in the DataTable. If the user clears the TextBox the filter is removed while if there is text filter with trim.
Private Sub SearchButton_Click(sender As Object, e As EventArgs) _
Handles SearchButton.Click
If String.IsNullOrWhiteSpace(SearchTextBox.Text) Then
bindingSource.Filter = ""
Else
Dim currentRowCount = bindingSource.Count
bindingSource.Filter = $"TRIM(LastName) = '{SearchTextBox.Text}'"
MessageBox.Show($"Before: {currentRowCount} Now: {bindingSource.Count}")
End If
End Sub
Edit If the column name might be variable consider loading a ComboBox with column names then adjust code as follows.
bindingSource.Filter = $"TRIM({FilterComboBox.Text}) = '{SearchTextBox.Text}'"
In most cases working against a data source is better than working against cells values as per the above recommendation.
I added 2 Exits in the IF statement when the value matches as it's searching each column as well, so it was causing them to be hidden as it loops columns too
For i As Integer = 0 To ContactsList.RowCount - 1
For j As Integer = 0 To ContactsList.ColumnCount - 1
If ContactsList.Rows(i).Cells(j).Value.ToString.ToLower.Trim = ContactsListSearch.Text.ToLower.Trim Then
MsgBox("Item found " + i.ToString)
ContactsList.Rows(i).Visible = True
Else
ContactsList.Rows(i).Visible = False
End If
Next
Next
I have a data grid view where I need the columns to be frozen or fixed when scrolling vertically.
I have a data grid view control in vb.net windows application which displays the data in a parent-child hierarchy(as shown below). The first column displays the parent data and the second column displays all its child data. The child data in the second column can be as much as 100 rows or even more. So when scrolling down through the grid, the value in the first column does not remain there as it is while the values in the second column(i.e. the child data) scrolls down. So if the user wants to check to which parent, the current child info belongs to, then again he will have to scroll up to the starting of the column to find the name of the parent. I want the values in the first column to be displayed or frozen till it reaches the end of the list of its child values in the grid or at least till the next row where the next parent data starts. I have suggested the client to go with a tree view but they are not agreeing and need it in a data grid view itself. Is there anyway to achieve this in a data grid view?
Thanks in advance.
You can't freeze a row (in runtime, on dgv scrolling) with index greater than zero because all those before are frozen and at that point you can't scroll your datagridview.
If I understood correctly what you want I wrote this class quickly (probably should be optimized). Usage is simple.
1 - First create your own datagridview.
2 - then add your columns and rows (IMPORTANT: Put a “X” in the Tag in each row is a Parent or is considered as title for other rows as you seen in TestPopulate method) .
3 - Call the class I made by passing the datagridview (you created first) as a parameter. At this point this control takes its size, placement and REPLACE YOUR DATAGRIDVIEW .
Private Class CustomDgv
Inherits Panel
Dim WithEvents TopDgv As DataGridView = New DataGridView
Dim WithEvents DownDgv As DataGridView = New DataGridView
Dim Cols As Integer
' This variable is in case you have more rows as "headrow"
' In TestPopulate you can see how to get those
Dim listOfOwnerRows As List(Of Integer) = New List(Of Integer)
Dim currentTopRow As Integer = -1
Protected Overloads Property Height As Integer
Get
Return MyBase.Height
End Get
Set(value As Integer)
MyBase.Height = value
TopDgv.Height = TopDgv.RowTemplate.Height - 1
DownDgv.Height = value - TopDgv.Height - 1
End Set
End Property
Protected Overloads Property Width As Integer
Get
Return MyBase.Width
End Get
Set(value As Integer)
MyBase.Width = value
TopDgv.Width = value - 1
DownDgv.Width = value - 1
End Set
End Property
Sub New(dgvOriginal As DataGridView)
DownDgv = dgvOriginal
Dim parentCtrl As Control = dgvOriginal.Parent
parentCtrl.Controls.Remove(dgvOriginal)
parentCtrl.Controls.Add(Me)
Me.Location = DownDgv.Location
Me.Size = DownDgv.Size
Me.BorderStyle = DownDgv.BorderStyle
TopDgv.Width = Width - 2 - SystemInformation.VerticalScrollBarWidth
TopDgv.Height = TopDgv.RowTemplate.Height
TopDgv.ScrollBars = ScrollBars.None
TopDgv.ColumnHeadersVisible = False
TopDgv.BorderStyle = BorderStyle.None
DownDgv.ColumnHeadersVisible = False
DownDgv.BorderStyle = BorderStyle.None
TopDgv.Left = 0
DownDgv.Left = 0
DownDgv.Width = Width - 2
DownDgv.Height = Height - 2
For Each Col As DataGridViewColumn In DownDgv.Columns
Dim cIndex As Integer = TopDgv.Columns.Add(Col.Clone)
If Col.Frozen Then
TopDgv.Columns(cIndex).Frozen = True
End If
Cols += 1
Next
DownDgv.Top = 0
Me.Controls.Add(TopDgv)
Me.Controls.Add(DownDgv)
If DownDgv.Rows.Count > 0 Then
listOfOwnerRows = (From R As DataGridViewRow In DownDgv.Rows
Where R.Tag = "X"
Select R.Index).ToList
If listOfOwnerRows.Count > 0 Then
SetFrosenRow(listOfOwnerRows(0))
End If
End If
End Sub
Protected Sub SetFrosenRow(index As Integer)
If DownDgv.Rows.Count > index Then
TopDgv.Rows.Clear()
TopDgv.Rows.Add()
Dim currentRIndex As Integer = DownDgv.FirstDisplayedScrollingRowIndex
'If you want onlly the base row
For i As Integer = 0 To Cols - 1
TopDgv.Rows(0).Cells(i).Value = DownDgv.Rows(index).Cells(i).Value
Next
'Or else get the diplayed on top row
TopDgv.Rows(0).DefaultCellStyle = New DataGridViewCellStyle With {
.BackColor = Color.Bisque
}
currentTopRow = index
End If
End Sub
Protected Sub SetChildValuesInTopRow(index As Integer)
For i As Integer = 1 To Cols - 1
TopDgv.Rows(0).Cells(i).Value = DownDgv.Rows(index).Cells(i).Value
Next
End Sub
Private Sub DownDgv_Scroll(sender As Object, e As ScrollEventArgs) Handles DownDgv.Scroll
Try
If e.ScrollOrientation = ScrollOrientation.VerticalScroll Then
Dim topR As Integer = DownDgv.FirstDisplayedScrollingRowIndex
'If you want in top row the current value that is in the top uncomment this
SetChildValuesInTopRow(topR)
If listOfOwnerRows.Count > 0 Then
Dim rToSetAsOwner As Integer = listOfOwnerRows(listOfOwnerRows.Count - 1)
For i As Integer = listOfOwnerRows.Count - 1 To 0 Step -1
If listOfOwnerRows(i) <= topR Then
rToSetAsOwner = listOfOwnerRows(i)
Exit For
End If
Next
If rToSetAsOwner <> currentTopRow Then
SetFrosenRow(rToSetAsOwner)
End If
Console.WriteLine("rToSetAsOwner: " & rToSetAsOwner)
End If
Else
TopDgv.HorizontalScrollingOffset = DownDgv.HorizontalScrollingOffset
End If
Catch ex As Exception
Console.WriteLine(ex.ToString)
End Try
End Sub
End Class
Usage:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Try
' first populate you grid putting a tag in each row which is a header/parent/title for other rows
TestPopulate()
Dim customControl As Control = New CustomDgv(DataGridView1)
Catch ex As Exception
Console.WriteLine(ex.ToString)
End Try
End Sub
Sub TestPopulate()
For i As Integer = 0 To 100
DataGridView1.Rows.Add()
If i = 0 Then
DataGridView1.Rows.Item(0).Cells(0).Value = "Owner 0"
DataGridView1.Rows(0).Tag = "X"
End If
If i = 50 Then
DataGridView1.Rows.Item(50).Cells(0).Value = "Owner 50"
DataGridView1.Rows(50).Tag = "X"
End If
If i = 70 Then
DataGridView1.Rows.Item(70).Cells(0).Value = "Owner 70"
DataGridView1.Rows(70).Tag = "X"
End If
DataGridView1.Rows.Item(i).Cells(1).Value = "child_" & i.ToString & "_1"
DataGridView1.Rows.Item(i).Cells(2).Value = "child_" & i.ToString & "_2"
Next
End Sub
I hope I have been helpful
Check if datatable has row at selected index using a for loop
i Want to check here if datatable has row at that value of 'i' which comes from loop
Private Sub btnAct_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAct.Click
Gross = 0
Dim i As Integer
Dim dr As DataRow = Nothing
Act1 = dt.Rows(0)("Account")
Act2 = dt.Rows(0)("Account")
'Next
For i = 0 To 100 Step 1
If ( i Want to check here if datatable has row at that value of 'i' which comes from loop) Then
else
If (Act1 = Act2) Then
Else
Act1 = dt.Rows(i - 1)("Account")
For k As Integer = 0 To (i - 1) Step 1
Act2 = Convert.ToString(dt.Rows(k)("Account"))
If (Act1 = Act2) Then
Gross += Convert.ToInt32(dt.Rows(k)("Total_Gross_Amount"))
End If
Next
dr = dt.NewRow()
dr("Account") = "Total"
dr("Total_Gross_Amount") = Gross
Gross = 0
dt.Rows.InsertAt(dr, i)
Act2 = Convert.ToString(dt.Rows(i + 1)("Account"))
End If
Act1 = Convert.ToString(dt.Rows(i + 1)("Account"))
dt(i)("Sno") = i + 1
Next
End If
'Next
End Sub
I have a datatable And I want to check it has row at selected value which comes from a for loop
Simple - LINQ to the rescue:
For i = 0 To 100
' Functionally equivalent to
' dt.Rows.Cast(Of DataRow)().ElementAtOrDefault(i).
Dim rowAtIndex = dt.AsEnumerable().ElementAtOrDefault(i)
If rowAtIndex IsNot Nothing Then
' Do something with the row.
End If
Next
Or a slightly less expressive, but better optimised version:
For i = 0 To 100
Dim rowAtIndex As DataRow = Nothing
If i < dt.Rows.Count Then
rowAtIndex = dt.Rows(i)
' Do something with the row.
Else
' Row at index does not exist.
End If
Next
The big question here is though: does i really need to go beyond dt.Rows.Count - 1 (which is the index of the last row in the DataTable)? If not, I'd rather change the loop to
For i = 0 To dt.Rows.Count - 1
I need to dynamically select an item in a listview based on what was selected previously.
The items that have been selected in the past are retrieved from a database and added to an Arraylist. These items then need to be selected from a number of different listviews.
Doing this by index like so listRef1.Items(2).Checked = True is no problem but I need to do it by the item text, i.e. one of the strings in the array.
So far I have this:
For i As Integer = 0 To refsArr.Count - 1
'find the correct category id
Dim cmdRefCat As New SqlCommand("SELECT RefID from ReferencesListTable WHERE RefName = '" & refsArr(i) & "'", conn)
Dim refid As Integer = cmdRefCat.ExecuteScalar()
If refid = 1 Then
listRef1.Items(refsArr(i)).Checked = True
ElseIf refid = 2 Then
listRef2.Items(refsArr(i)).Selected = True
listRef2.Select()
ElseIf refid = 3 Then
listRef3.Items.Item(refsArr(i)).Selected = True
listRef2.Select()
ElseIf refid = 4 Then
listRef4.Items.Item(refsArr(i)).Selected = True
End If
Next
Has anyone got any ideas on this? Thanks.
You'll need to loop through each item in the listview list:
For I as Integer = 0 to ListView.Items.Count - 1 Do
If ListView.Items(i).Text = "Text" then
ListView.Items(i).Selected = true
End If
End For
You can try this ...
For i As Integer = 0 To refsArr.Count - 1
'find the correct category id
Dim cmdRefCat As New SqlCommand("SELECT RefID from ReferencesListTable WHERE RefName = '" & refsArr(i) & "'", conn)
Dim refid As Integer = cmdRefCat.ExecuteScalar()
Select case refid
case 1
CheckIt(refsArr(i),listRef1)
case 2
CheckIt(refsArr(i),listRef2)
case 3
CheckIt(refsArr(i),listRef3)
case 4
CheckIt(refsArr(i),listRef4)
End Select
Next
And Sub CheckIt
Sub CheckIt(ByVal sRef as String, ByRef lvw as Listview)
Dim x as Integer
For x = 0 to lvw.Items.Count - 1
If lvw.Items(x).Text = sRef then
lvw.Items(x).Selected = true
exit for '-- if only 1 record
End If
Next
End Sub
The code to select an item dynamically from the listview control can be as follows for vb.net.
Let lvwomominiChair1 is the name of the listview control.
Set its fullrowselect property as true.
The code will select the text in the first column of the listview control.
Private Sub lvwomominiChair1_Click(sender As Object,e As EventArgs) Handles lvwomominiChair1.Click
Dim lvwitem as ListViewItem
lvwitem = lvwomominiChair1.SelectedItems.Item(0)
MsgBox("Selected item is " + lvwitem.Text)
End Sub
There may be situations where we need to get all items in a row of a ListView control.The following code may be used for the purpose.It is assumed that there are five columns of data in a raw and are of the text data type.This can be done with a For..Next loop as follows.Let 0,1,2,3 and 4 are the five column indices.
Private Sub lvwomominiChair1_Click(sender As Object,e As EventArgs) Handles lvwomominiChair1.Click
Dim i As Int32
Dim str As String
str =""
For i =0 To 4
str = str + " " + lvwomominiChair1.SelectedItems(0).SubItems(i).Text
Next
MsgBox("Selected items of the five columns of the row are " + str)
End Sub
Or you can do this, works perfect for me:
ListView.Items(0).Selected = True
ListView.Select()
This program suppose to sort records(in arySort) in ascending order by last name(index 1 in aryTemp and aryTemp2) and place the result in the list box over the old, preloaded, unsorted records.
It sorts them strangely, I have to click multiple times the Ascending button to get the actual sort result that I suppose to get from clicking the button once.
Why doesn't it sort items with a single mouse click?
The source:
Public Class Form1
Dim FILE_NAME As String = "Students.txt"
Dim numberOfRecords As Integer 'total number of records
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
If System.IO.File.Exists(FILE_NAME) = True Then
Dim objReader As New System.IO.StreamReader(FILE_NAME)
Do While objReader.Peek() <> -1
lstBox.Items.Add(objReader.ReadLine)
numberOfRecords += 1
Loop
objReader.Close()
End If
End Sub
Private Sub btnAscending_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAscending.Click
'load all students into array
Dim arySort(numberOfRecords - 1) As String
Dim aryTemp() As String 'holds first record's last name
Dim aryTemp2() As String 'holds second record's last name
For i = 0 To numberOfRecords - 1
arySort(i) = lstBox.Items(i)
Next
Dim temp As String 'holds temporary record
Dim k As Integer
For i = 0 To arySort.Length - 2
aryTemp = Split(arySort(i), " ")
For k = i + 1 To arySort.Length - 1
aryTemp2 = Split(arySort(k), " ")
If aryTemp(1) < aryTemp2(1) Then
temp = arySort(k)
arySort(k) = arySort(i)
arySort(i) = temp
End If
Next
Next
lstBox.Items.Clear()
numberOfRecords = 0
For i = 0 To arySort.Length - 1
lstBox.Items.Add(arySort(i))
numberOfRecords += 1
Next
End Sub
End Class
If you just need to sort your list (as you say in the comment), don't implement your own sort mechanism but use the one of .NET:
' Define how we want to compare items '
Function compareByLastName(ByVal item1 As String, ByVal item2 As String) As Integer
Return String.Compare(item1.Split(" ")(1), item2.Split(" ")(1))
End Function
Private Sub btnAscending_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAscending.Click
' load all students into array '
Dim arySort(numberOfRecords - 1) As String
For i = 0 To numberOfRecords - 1
arySort(i) = lstBox.Items(i)
Next
' Use built-in .NET magic '
Array.Sort(arySort, AddressOf compareByLastName)
' Write the values back into your list box '
lstBox.Items.Clear()
numberOfRecords = 0
For i = 0 To arySort.Length - 1
lstBox.Items.Add(arySort(i))
numberOfRecords += 1
Next
End Sub
This uses the built-in quicksort algorithm of the .NET class library. Here's the documentation of the method we are using: Array.Sort(T(), Comparison(Of T)).
compare with my working bubble sort:
Public Sub BubbleSort(ByVal arr() As Integer)
Dim flag As Boolean = False
For i As Integer = 0 To arr.Length - 1
For j As Integer = 0 To arr.Length - 2 - i
If arr(j + 1) < arr(j) Then
flag = True
Dim temp As Integer = arr(j)
arr(j) = arr(j + 1)
arr(j + 1) = temp
End If
Next
If flag = False Then Return ' no swaps =>already sorted
Next
End Sub
I see a two major issues with your algorithm:
It's not bubble sort. Bubble sort swaps adjacent elements, i.e., it swaps i with i+1. You, on the other hand, swap some element i with the first j > i where name(i) < name(j). Maybe you should show us, in pseudo code, which algorithm you are actually trying to implement?
aryTemp contains element i and aryTemp2 contains some element j > i. Why do you swap the elements if aryTemp(1) < aryTemp2(1)? Isn't that already the correct order if you want your elements to be sorted ascending?