Search code examples
arraysvb.nettext-filesread-write

(VB.NET) display the lower half of a textfile to a listbox


I have to make a application that organizes a list of runners and their teams. In the following text file, I have to remove the top half of the text file (the top half being the listed teams) and display only the bottom half (the runners)in a listbox item.

The Text file:

 # School [School Code|School Name|Coach F-Name|Coach L-Name|AD F-Name|AD L Name]
 WSHS|Worcester South High School|Glenn|Clauss|Bret|Zane
 WDHS|Worcester Dorehty High School|Ellsworth|Quackenbush|Bert|Coco
 WBCHS|Worcester Burncoat High School|Gail|Cain|Kevin|Kane
 QRHS|Quabbin Regional High School|Bob|Desilets|Seth|Desilets  
 GHS|Gardner High School|Jack|Smith|George|Fanning   
 NBHS|North Brookfield High School|Hughe|Fitch|Richard|Carey
 WHS|Winchendon High School|Bill|Nice|Sam|Adams
 AUBHS|Auburn High School|Katie|Right|Alice|Wonderland
 OXHS|Oxford High School|Mary|Cousin|Frank|Daughter
 # Roster [Bib #|School Code|Runner's F-Name|Runner's L-Name]
 101|WSHS|Sanora|Hibshman
 102|WSHS|Bridgette|Moffitt
 103|WSHS|Karine|Chunn
 104|WSHS|Shanita|Wind
 105|WSHS|Fernanda|Parsell
 106|WSHS|Albertha|Baringer
 107|WSHS|Carlee|Sowards
 108|WDHS|Maisha|Kleis
 109|WDHS|Lezlie|Berson
 110|WDHS|Deane|Rocheleau
 111|WDHS|Hang|Hodapp
 112|WDHS|Zola|Dorrough
 113|WDHS|Shalon|Mcmonigle

I have some code that reads each row from the text file as an array and uses boolean variables to determine where to end the text file. This worked with displaying only the teams, which I've managed to do. But I now need to do the opposite and display only the players, and I'm a bit stumped.

My Code:

   Private Sub btnLoadTeams_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLoadTeam.Click
    ' This routine loads the lstTeam box from an ASCII .txt file
    ' # School [School Code | Name | Coach F-Name| Coach L-Name | AD F-Name | AD L-Name]

    Dim strRow As String
    Dim bolFoundCode As Boolean = False
    Dim bolEndCode As Boolean = False
    Dim bolFoundDup As Boolean = False
    Dim intPosition As Integer
    Dim intPosition2 As Integer
    Dim strTeamCodeIn As String
    Dim textIn As New StreamReader( _
        New FileStream(txtFilePath.Text, FileMode.OpenOrCreate, FileAccess.Read))
    ' Clear Team listbox
    lstTeam.Items.Clear()
    btnDeleteRunner.Enabled = True

    Do While textIn.Peek <> -1 And Not bolEndCode
        Me.Refresh()
        strRow = textIn.ReadLine.Trim
        If Not bolFoundCode Then
            If "# SCHOOL " = UCase(Mid(strRow, 1, 9)) Then
                bolFoundCode = True
            End If
        Else
            If Mid(strRow, 1, 2) <> "# " Then
                For Each item As String In lstTeam.Items
                    intPosition = InStr(1, strRow, "|")
                    strTeamCodeIn = Mid(strRow, 1, intPosition - 1)
                    intPosition2 = InStr(1, item, strTeamCodeIn)

                    If intPosition2 > 0 Then
                        bolFoundDup = True
                        MsgBox("Found Duplicate School Code: " & strTeamCodeIn)

                    End If
           Else
               bolEndCode = True
                Next

                If Not bolFoundDup Then
                    lstTeam.Items.Add(strRow)

                Else
                    lstTeam.Items.Add("DUPLICATE School Code: " & strRow)
                    lstTeam.Items.Add("Please correct input file and reload teams")
                    bolEndCode = True
                End If
            End If
        End If
    Loop

End Sub

Ive put bolEndCode = True in between the part that reads the mid section of the text file, but all Ive managed to display is the following in the listbox:

 # Roster [Bib #|School Code|Runner's F-Name|Runner's L-Name]

Any help or hints on how I would display just the runners to my "lstPlayers" listbox would be greatly appreciated. I'm a beginner programmer and We've only just started learning about reading and writing arrays in my .NET class.


Solution

  • First I made 2 classes, one Runner and one School. These have the properties available in the text file. As part of the class I added a function that overrides .ToString. This is for he list boxes that call .ToString for display.

    Next I made a function that reads all the data in the file. This is very simple with the File.ReadLines method.

    Then I created 2 variables List(Of T) T stands for Type. Ours Types are Runner and School. I used List(Of T) instead of arrays because I don't have to worry about what the size of the list is. No ReDim Preserve, just keep adding items. The FillList method adds the data to the lists. First I had to find where the schools ended and the runners started. I used the Array.FindIndex method which is a bit different because the second parameter is a predicate. Check it out a bit. Now we know the indexes of the lines we want to use for each list and use a For...Next loop. In each loop an instance of the class is created and the properties set. Finally the new object is added to the the list.

    Finally we fill the list boxes with a simple .AddRange and the lists.ToArray. Note that we are adding the entire object, properties and all. The neat thing is we can access the properties from the listbox items. Check out the SelectedIndexChanged event. You can do the same thing with the Runner list box.

    Sorry, I couldn't just work with your code. I have all but forgotten the old vb6 methods. InStr, Mid etc. It is better when you can to use .net methods. It makes your code more portable when the boss says "Rewrite the whole application in C#"

    Public Class Runner
        Public Property BibNum As Integer
        Public Property SchoolCode As String
        Public Property FirstName As String
        Public Property LastName As String
        Public Overrides Function ToString() As String
            'The listbox will call .ToString when we add a Runner object to determin what to display
            Return $"{FirstName} {LastName}" 'or $"{LastName}, {FirstName}"
        End Function
    End Class
    
    Public Class School
        Public Property Code As String
        Public Property Name As String
        Public Property CoachFName As String
        Public Property CoachLName As String
        Public Property ADFName As String
        Public Property ADLName As String
    
        'The listbox will call .ToString when we add a School object to determin what to display
        Public Overrides Function ToString() As String
            Return Name
        End Function
    
    End Class
    
    Private Runners As New List(Of Runner)
    Private Schools As New List(Of School)
    Private Function ReadData(path As String) As String()
        Dim lines = File.ReadLines(path).ToArray
        Return lines
    End Function
    
    Private Sub FillLists(data As String())
        Dim location = Array.FindIndex(data, AddressOf FindRosterLine)
        'The first line is the title so we don't start at zero
        For index = 1 To location - 1
            Dim SplitData = data(index).Split("|"c)
            Dim Schl As New School
            Schl.Code = SplitData(0)
            Schl.Name = SplitData(1)
            Schl.CoachFName = SplitData(2)
            Schl.CoachLName = SplitData(3)
            Schl.ADFName = SplitData(4)
            Schl.ADLName = SplitData(5)
            Schools.Add(Schl)
        Next
        For index = location + 1 To data.GetUpperBound(0)
            Dim SplitData = data(index).Split("|"c)
            Dim Run As New Runner
            Run.BibNum = CInt(SplitData(0))
            Run.SchoolCode = SplitData(1)
            Run.FirstName = SplitData(2)
            Run.LastName = SplitData(3)
            Runners.Add(Run)
        Next
    End Sub
    
    Private Function FindRosterLine(s As String) As Boolean
        If s.Trim.StartsWith("# Roster") Then
            Return True
        Else
            Return False
        End If
    End Function
    
    Private Sub FillListBoxes()
        Dim arrRunners As Runner() = Runners.ToArray
        Dim arrSchools As School() = Schools.ToArray
        ListBox1.Items.AddRange(arrSchools)
        ListBox2.Items.AddRange(arrRunners)
    End Sub
    
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim arrRunner = ReadData("Runners.txt")
        FillLists(arrRunner)
        FillListBoxes()
    End Sub
    
    Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedIndexChanged
        Dim Schl = DirectCast(ListBox1.SelectedItem, School)
        TextBox1.Text = Schl.CoachLName
        TextBox2.Text = Schl.Code
    End Sub