Jim
Jim

Reputation: 17

vb.net Save/Load file and other issues

I'm creating a simple program that could be used to save contacts and information on its contact. I have trouble with the save/load functions and the total count of inserted contacts. Most code is taken from a tutorial of "TheNewBoston" and since I liked it I try to add more features. Here is the source code:

Public Class Form1

    Dim myCustomers As New ArrayList
    Dim FILE_NAME As String = "C:\test.txt"

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        AddCustomer("Sam", "Bond", "[email protected]", "9541032163")
        AddCustomer("Merry", "Jackson", "[email protected]", "8872101103")
        AddCustomer("Rachel", "Smith", "[email protected]", "4839078565")
        'DOESN'T WORK''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
        If System.IO.File.Exists(FILE_NAME) = True Then
            'AddCustomer.System.IO.StreamReader(FILE_NAME)
            'or
            AddCustomer(System.IO.StreamReader(FILE_NAME))
        Else
            MessageBox.Show("File does not exist.")
        End If
    End Sub

    'Public variables
    Private Structure Customer
        Public FirstName As String
        Public LastName As String
        Public Email As String
        Public Phone As Decimal

        'Does Name = First&Last Name
        Public ReadOnly Property Name() As String
            Get
                Return FirstName & " " & LastName
            End Get
        End Property

        'Shows the customers in the listbox properly overriding the default ToString function
        Public Overrides Function ToString() As String
            Return Name
        End Function

    End Structure

    'Declaring and connecting to type Customer
    Private objCustomer As Customer
    Private objNewCustomer As Customer

    'Makes customer format
    Private Sub AddCustomer(ByVal firstName As String, ByVal lastName As String, ByVal email As String, ByVal phone As Decimal)
        'declares objNewCustomer with the type of customer for use
        Dim objNewCustomer As Customer

        'Connects the Customer's 4 things to objNewCustomer
        objNewCustomer.FirstName = firstName
        objNewCustomer.LastName = lastName
        objNewCustomer.Email = email
        objNewCustomer.Phone = phone

        'Adds to myCustomers array list the objNewCustomer
        myCustomers.Add(objNewCustomer)
        'Adds customer Name to list
        listCustomers.Items.Add(objNewCustomer.ToString())
    End Sub

    'Avoids customer select error
    Private ReadOnly Property SelectedCustomer() As Customer
        Get
            If listCustomers.SelectedIndex <> -1 Then
                Return CType(myCustomers(listCustomers.SelectedIndex), Customer)
            End If
        End Get
    End Property

    'Enables select customer
    Private Sub listCustomers_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles listCustomers.SelectedIndexChanged
        DisplayCustomer(SelectedCustomer)
    End Sub


    'Loads the customers' information
    Private Sub DisplayCustomer(ByVal cust As Customer)
        txtName.Text = cust.Name
        txtFirstName.Text = cust.FirstName
        txtLastName.Text = cust.LastName
        txtEmail.Text = cust.Email
        txtPhone.Text = cust.Phone
    End Sub


    'Add User (pops up new window)
    Private Sub btnAdd_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAdd.Click
        Form2.Show()
        'System.IO.File.WriteAllText("C:\test.txt", Textbox1.Text)
    End Sub

    'WORKS
    Private Sub btnTotal_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnTotal.Click
        txtTotal.Text = myCustomers.Count.ToString()
    End Sub

    'Private Total2 As Integer
    'experimenting
    'Private Sub DisTotal(ByVal Total As Integer)
    '    Do
    '        'total2 = myCustomers.Count.ToString()
    '        'txtTotal.Text = total2
    '        txtTotal.Text = Total
    '        System.Threading.Thread.Sleep(5000)
    '    Loop
    'End Sub

    Private Sub listTotal_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
        Total = myCustomers.Count
        'DOESN'T WORK''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
        Do
            'total2 = myCustomers.Count.ToString()
            'txtTotal.Text = total2
            txtTotal.Text = myCustomers.Count.ToString()
            System.Threading.Thread.Sleep(5000)
        Loop
    End Sub

    Private Total As Integer
    'DOESN'T WORK''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSave.Click
        Dim writer As New IO.StreamWriter(FILE_NAME)

        Try
            writer.Write("")
            writer.Close()
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        Finally
            writer.Close()
        End Try
    End Sub End Class

Any help/hint appreciated and also if you post corrected code blocks please explain how it works/what was wrong too, thanks.

Upvotes: 0

Views: 1198

Answers (1)

J...
J...

Reputation: 31463

You are trying to use a stream reader as arguments to your AddCustomer function - this will not work. In fact, you can't use a StreamReader in the manner you are declaring it at all - you have to instantiate one like this :

 Dim sr as New StreamReader
 Dim line as String
 line = sr.ReadLine()

and so on. See the documentation for more details.

In any case, if you are trying to read customer data from a comma-separated file, for example like this :

C:\test.text --- contains :

Sam, Bond, [email protected], 9541032163
Merry, Jackson, [email protected], 8872101103
Rachel, Smith, [email protected], 4839078565

Then you would have to do something like this to read the values in -- note that we have to pass the arguments to AddCustomer in the way that the function is declared (ie: four strings!) :

If System.IO.File.Exists(FILE_NAME) Then
    'Using creates an instance and disposes it for you when you leave the block
    Using Rdr As New Microsoft.VisualBasic.FileIO.TextFieldParser(FILE_NAME)
        'Indicates the values are delimited (separated by a special character)
        Rdr.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited
        'Defines the array of special characters that separate fields
        Rdr.Delimiters = New String() {","}
        'Declare a string array to hold the data from each line
        Dim currentRow As String()
        'Read lines until you reach the end of the file
        While (Not Rdr.EndOfData)
            'For each line, read and parse the data
            currentRow = Rdr.ReadFields()
            'Data are stored with zero-based index
            Dim firstName As String = currentRow(0)
            Dim lastName As String = currentRow(1)
            Dim emailAdd As String = currentRow(2)
            Dim phNum As String = currentRow(3)
            AddCustomer(firstName, lastName, emailAdd, phNum)
        End While
    End Using
Else
    MessageBox.Show("File does not exist.")
End If

The text field parser reads to a string array and automatically separates the values into array columns for you. If the data is TAB separated then you simply would change the delimiter as in

Rdr.Delimiters = New String() {"vbTab"}

This is an array parameter so you can even do a mix of spaces, tabs, commas, etc. Just add them to the list like Rdr.Delimiters = New String() {"vbTab", " ", ","}.

Using a text field parser is nice because it can read in tab or comma separated values as generated by something like Excel. Take care that I have not shown any exception handling in the above code. It is probably prudent to wrap a few of those sections in try/except blocks in the case that the file is not correctly formatted, can't be read, etc.

see : TextFieldParser (MSDN) for more information

EDIT

I see I missed the second part of this question. First, I would suggest using generics for your customer list

Dim myCustomers As New List(Of Customer)

This is much nicer for a lot of reasons (read up on generics/collections for more info). Of primary importance, they give you type-safety. Also you get a lot of other goodies in terms of searching and sorting, etc.

As for your loop :

Do
    'total2 = myCustomers.Count.ToString()
    'txtTotal.Text = total2
    txtTotal.Text = myCustomers.Count.ToString()
    System.Threading.Thread.Sleep(5000)
Loop

This will never terminate (there are no conditions on the Do part, so it will just keep looping forever!). Usually Do loops are done like

Do while x < 10
   x = x + 1
   DoSomething()
Loop

In your case it will never end. The call to Sleep is also completely unnecessary. You should never, ever sleep the UI thread! All you need to do here is :

txtTotal.Text = myCustomers.Count.ToString()

That's it - no Do/Loop, no sleep. Job done.

See also : Do..Loop (MSDN)

Upvotes: 2

Related Questions