I am new to Vb.net so I will need some handholding. I have been searching everywhere but can't find what I need.

I'm creating an app that has two forms.
Each form has two comboboxes.
The comboboxes are populated via a list and the list is populated by reading a text file for each combobox.
The second form is called from the main form to modify the entries in the comboboxes.
When I select the displaymember in the combobox a value corresponding to that entry is displayed in the text box.

Now here is what I need.

I need to be able to append new values to the list so when focus is returned to the main form the new value is present. I'm using a combobox and a textbox on the second form as the import.
The combobox is used to either select a present value to be able to modify the value in the textbox, or is used to add a new list element.


Secondly at the time the new values are entered into the list, I need these values to be written to the text file as well, so the new element can be available in the list the next time the app is started.
The format of the text file is

Carpenter|55.00
Laborer|18.00
Operator|25.00

Here is the code that populates one of the comboboxes, the second list is basically the same but it has an additional value

Pick Up|15.00|4.00
Loader|25.00|12.00

Private Sub LoadTCComboBoxes()
        Try
            For Each ctl As Control In Me.gboTradeClass.Controls
                If TypeOf ctl Is ComboBox Then
                    tradeList = TradeClassDB.GetTradeList
                    DirectCast(ctl, ComboBox).DataSource = tradeList
                    DirectCast(ctl, ComboBox).DisplayMember = "TradeClass_Description"
                    DirectCast(ctl, ComboBox).SelectedIndex = -1
                End If
            Next

        Catch ex As Exception
            MessageBox.Show(ex.Message, ex.GetType.ToString)
        End Try
    End Sub

I do have another issue and that is sorting the displaymember and other values in the combobox so they are in alphabetical order with thier associated values.

Thanks in advance. I hope I wasn't too long winded.

Rob

Recommended Answers

All 17 Replies

Easiest one first. set the Sort property of the ComboBox to True and the items will display sorted.

The comboboxes are populated via a list and the list is populated by reading a text file for each combobox.

What is the type of your list? A "list" can be many different things. It can be a ListBox, a ListView, any one of the Microsoft supplied list types or even a custom list class. Without a declared type I have no way of answering the list question.

Ditto for the "how to write a list to a text file". I can't definitively answer this without knowing the form of your list.

Hi Reverend Jim

The list is a Typed Collection List. Below is the code I use to read the text file into the list. The code I provided previously populates the comboboxes.

I hope this helps to clarify.

Public Shared Function GetTradeList() As List(Of Trade)

        Dim textIn As New StreamReader(New FileStream(Path, FileMode.Open, FileAccess.Read))

        Dim tradelist As New List(Of Trade)

        Do While textIn.Peek <> -1
            Dim row As String = textIn.ReadLine
            Dim columns() As String = row.Split(CChar("|"))
            Dim trade As New Trade
            ' trade.TradeClass_ID = columns(0)
            trade.TradeClass_Description = columns(0)
            trade.Cost = CDec(columns(1))
            tradelist.Add(trade)
        Loop

        textIn.Close()
        Return tradelist

    End Function

Thanks for your reply
Rob

Sort of the same question as before but further into the stack - now can you please define what "Trade" is. Please don't say "it's a class". Define it so I can code you an example and I don't want to make any assumptions.

As an interim guess, you can read/write the tradeslist as follows (I assumed a default definition for Trade)

Public Class Form1

    Public tradelist As New List(Of Trade)

    Public Class Trade

        Public Name As String
        Public Wage As Double

        Public Sub New(name As String, wage As Double)
            Me.Name = name
            Me.Wage = wage
        End Sub

        Public Sub New(name As String, wage As String)
            Me.Name = name
            Me.Wage = CDbl(wage)
        End Sub

    End Class

    Private Sub btnImport_Click(sender As System.Object, e As System.EventArgs) Handles btnImport.Click

        Dim trades() As String = ReadFile("d:\temp\trades.txt")

        For Each line As String In trades
            Dim fields() As String = line.Split("|")
            If UBound(fields) = 1 Then
                tradelist.Add(New Trade(fields(0), fields(1)))
            End If
        Next

    End Sub

    Private Function ReadFile(filename As String) As String()

        Dim text As String = My.Computer.FileSystem.ReadAllText(filename)
        text = text.Replace(vbCr, "")
        Return text.Split(vbLf)

    End Function

    Private Sub WriteFile(filename As String, text As String)

        My.Computer.FileSystem.WriteAllText(filename, text, False)

    End Sub

    Private Sub btnExport_Click(sender As System.Object, e As System.EventArgs) Handles btnExport.Click

        Dim text As String = ""

        For Each trade As Trade In tradelist
            text = text & trade.Name & "|" & trade.Wage & vbCrLf
        Next

        WriteFile("d:\temp\trades.txt", text)

    End Sub

End Class

Unless text files are prohibitively large I prefer to read and write them in one chunk rather than use streams. Error checking is up to you.

Reverend Jim,
I'm not sure how to answer your previous question about Trade. I'm not sure what your asking.

Thanks for the code. I will work with it over the weekend and keep you updated.

Thanks again

What I meant was that I didn't know what the makeup of "Trade" was. tradelist is a List of Trades but because I didn't know for sure what a Trade looked like I made an assumption that it was a class with two properties. I don't know what the third value is in your second list.

OK, I understand now.

Here is the code for the 'Trade' and 'TradeClass' classes.
I just now getting the chance to work with the code you submitted. Thanks again.

Public Class Trade
    Private m_TradeClass_ID As String
    Private m_TradeClass_Description As String
    Private m_Cost As Decimal

    Public Sub New()

    End Sub

    'Public Property TradeClass_ID() As String
    '    Get
    '        Return m_TradeClass_ID
    '    End Get
    '    Set(ByVal value As String)
    '        m_TradeClass_ID = value
    '    End Set
    'End Property

    Public Property TradeClass_Description() As String
        Get
            Return m_TradeClass_Description
        End Get
        Set(ByVal value As String)
            m_TradeClass_Description = value
        End Set
    End Property

    Public Property Cost() As Decimal
        Get
            Return m_Cost
        End Get
        Set(ByVal value As Decimal)
            m_Cost = value
        End Set
    End Property

End Class
Imports System.IO

Public Class TradeClassDB

    ' Private Const Dir As String = "..\..\"
    Private Const Path As String = "tradeclasses.txt"

    Public Shared Function GetTradeList() As List(Of Trade)

        'If Not Directory.Exists(Dir) Then
        '    Directory.CreateDirectory(Dir)
        'End If

        Dim textIn As New StreamReader(New FileStream(Path, FileMode.Open, FileAccess.Read))

        Dim tradelist As New List(Of Trade)

        Do While textIn.Peek <> -1
            Dim row As String = textIn.ReadLine
            Dim columns() As String = row.Split(CChar("|"))
            Dim trade As New Trade
            ' trade.TradeClass_ID = columns(0)
            trade.TradeClass_Description = columns(0)
            trade.Cost = CDec(columns(1))
            tradelist.Add(trade)
        Loop

        textIn.Close()
        Return tradelist

    End Function


    Public Shared Sub SaveTradeList(ByVal tradelist As List(Of Trade))

        Dim textOut As New StreamWriter(New FileStream(Path, FileMode.Create, FileAccess.Write))

        For Each Trade As Trade In tradelist
            'textOut.Write(Trade.TradeClass_ID & "|")
            textOut.Write(Trade.TradeClass_Description & "|")
            textOut.WriteLine(Trade.Cost)
        Next

        textOut.Close()
    End Sub

End Class

I forgot to include what the third value is on the second list it is the fuel cost for the equipment.

The two lists are Labor and equipment. The labor list has the trade of the trades person and the cost per hour. The second list is the description of the equipment used, the cost per hour and the fuel cost per hour.

I have the list populating the combo boxes and when I select the combo box the proper hourly cost and fuel cost is selected, this is working perfectly.

My issue is that I just can not figure out is how to modify the lists through the Administration form.

The Admin form has a section for each list, each section has a combo box and a text box for each of the hourly rates. The user Should ne able to select a present entry and modify the description, and/or hourly rates, or click the NEW button to clear the controls and type in the new entries values. If they select a value in the combo box and click the Delete button the entry should be deleted. The list has to be sorted alphabetically before being written back to the file.

I can't figure out how to do this CRUD function to a collection list. All the examples I've found use constants with a single value per line and none should how to insert from a control or how to insert the "|" between values on the same line.

I hope this helps make it clearer.

Thanks

Not really. Why don't you zip and post the project and I can have a look. I really hope you have commented your code (that was a hint).

Here is the project.

You have to create a data entry form for Trade and Equipment. The data entry form will be called as a modal dialog in the btnTCNew_Click handler. That form will do the data entry and validation on the new values and call the tradelist.Add method if the validation succeeds and the user cliks an Add or OK button on that form. You might want to reread my hint in the previous posting. Your comments are sorely lacking. They should be written BEFORE the code.

For example, I created a form named frmEditTrade. In your frmAdministration I added

Private Sub btnTCNew_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnTCNew.Click
    If frmEditTrade.ShowDialog() = Windows.Forms.DialogResult.OK Then
        MsgBox(frmEditTrade.txtName.Text & " " & frmEditTrade.txtSalary.Text)
    End If
End Sub

You can replace the MsgBox with the code to add a new object to tradeslist. You should check before you add it to verify that it is not already in the list. The data entry form I provided is minimal. It does no checking to verify that the salary is numeric and reasonable.

And I can't emphasize enough about the comments. If I seem to be nagging about that it is because I spent over 30 years as a programmer, a lot of which was maintaining end enhancing other people's code. I was also a marker in university. Bad or no comments = bad grade.

"You can replace the MsgBox with the code to add a new object to tradeslist."

That is my problem. I do not know how to write the code that does this.
I do not know how to get the text properties of the controls into the tradeslist.

Then once it is added to tradeslist. How do I sort tradeslist and save it to the tradeclasses.txt so that way it is already sorted for when the combobox in frmAdministration is populated?

Thanks for all your help on this so far.

OK. I handled how to add a Trade to tradeslist in an earlier example. My example overloaded the New method so I could do

tradelist.Add(New Trade(frmEditTrade.txtName.Text, frmEditTrade.txtSalary.Text)

That won't add the trade in sorted order. However, because the combobox has a Sorted property so that the entries ARE sorted it doesn't really matter if the list and text file are not sorted.

Yes I ran the code you provided earlier, unfortunately it displays the description and the 'Wage' in the combobox. Ex. Carpenter|12.00.

This is not the result I'm looking for.

If you run my Administration form and select a trade from the combobox it displays ONLY the description and the Wage and Fuel values is displayed in the respective textboxes.

The pipe '|' is used to seperate these values in the tradelist.txt file so when the Streamreader reads the tradeslist.txt file it can seperate these values into trade.TradeClass_Description and trade.Cost in the list.

Excerpt from TradesClassDB


Dim textIn As New StreamReader(New FileStream(Path, FileMode.Open, FileAccess.Read))

Dim tradelist As New List(Of Trade)

Do While textIn.Peek <> -1
Dim row As String = textIn.ReadLine
Dim columns() As String = row.Split(CChar("|"))
Dim trade As New Trade
' trade.TradeClass_ID = columns(0)
trade.TradeClass_Description = columns(0)
trade.Cost = CDec(columns(1))
tradelist.Add(trade)
Loop

textIn.Close()
Return tradelist

As for sorting... If you are referring to the Sorted property that you can select in the Visual Studio's properties window, I tried that, it only sorts the Display Member and does not sort by the Selected Index, resulting in the Wage and Fuel values being incorrect for the trade selected in the combobox.

I figured since the tradelist.txt will be rewritten during CRUD, it is the perfect place to perform the sort before the write.

The Administration form is a very small part of my overall project and I don't want to mess with that other code now that it has been debugged and working perfectly. This is the only missing piece.

Thanks again.

The code I provided earlier was before I knew what your data structures were. It was intended to show you how to import and export the lists.

I don't see the problem. I ran your code with my mods and it does what you said you wanted.

And once again, why worry about sorting when the combobox does that for you?

I am not familiar with CRUD.

Member Avatar for Unhnd_Exception

A different approach.

Complete simple example. I don't care what your trade class is. This is for example and you should be able to build from it.

Fills a combobox from a textfile. Opens an edit form to add and edit items in the textfile. Reloads the combobox when editing complete. All data is displayed sorted by name.

The text file in this example is in the format of Name, Cost
Carpenter, 55
Programmer, 44
...

Provides two methods for data. List(of Trade) and DataTable.

Requires 2 Forms, 1 Module, and a Text File

The Main Form Form1
Fills a combobox with a sorted list of Trade and calls the edit form
to make changes.

Public Class Form1

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        'Sets the combo's datasource to the file
        'Uses a list of trade but the ReadTradeTable
        'would do the same thing.
        ComboBoxTrades.DisplayMember = "Name"
        ComboBoxTrades.ValueMember = "Cost"
        ComboBoxTrades.DataSource = DataAccess.ReadTradeList
    End Sub

    Private Sub ButtonEditTrades_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonEditTrades.Click
        If My.Forms.FormEdit.ShowDialog = Windows.Forms.DialogResult.OK Then
            'Reloads the combobox on ok
            'TradeList is sorted before it is returned
            ComboBoxTrades.DataSource = DataAccess.ReadTradeList
        End If
    End Sub

End Class

The Edit Form
Uses a data grid view to make changes to the data. Why not use a data grid view. You can edit and add new rows and microsoft did all the work for you. It requires a datatable though. So I added the data table example.

Public Class FormEdit

    Private Sub FormEdit_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        'Uses a gridview to add and edit items.
        'This uses a table so new rows can be added.
        'To use a list you would have to create a class
        'that inherited from list of trade and implemented
        'Ibindinglist.  Table is easier

        DataGridViewTrades.DataSource = DataAccess.ReadTradeTable
        DataGridViewTrades.Sort(DataGridViewTrades.Columns("Name"), System.ComponentModel.ListSortDirection.Ascending)
    End Sub

    Private Sub ButtonOk_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonOk.Click
        'Ok pressed
        'Write the new data.
        DataAccess.WriteTradeList(CType(DataGridViewTrades.DataSource, DataTable))
        Me.DialogResult = Windows.Forms.DialogResult.OK
    End Sub

    Private Sub DataGridViewTrades_CellValidating(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellValidatingEventArgs) Handles DataGridViewTrades.CellValidating
        'You can validate with CellValidating
        'This doesn't allow a non numeric number to be
        'entered into the cost field.
        If DataGridViewTrades.Columns(e.ColumnIndex).Name = "Cost" Then
            If Not IsNumeric(e.FormattedValue) Then
                e.Cancel = True
            End If
        End If
    End Sub

End Class

The Data Module.
Used to read and write from your data source. A text file
Can handle a list or data table.

Module DataAccess

    'Trade of your choice.  Example
    Public Class Trade
        Private fpName As String
        Private fpCost As Single

        Property Name() As String
            Get
                Return fpName
            End Get
            Set(ByVal value As String)
                fpName = value
            End Set
        End Property

        Property Cost() As Single
            Get
                Return fpCost
            End Get
            Set(ByVal value As Single)
                fpCost = value
            End Set
        End Property

        Sub New(ByVal name As String, ByVal cost As Single)
            fpName = name
            fpCost = cost
        End Sub
    End Class

    'Custom comparer to sort the trades by name
    'See it work in ReadTradeList
    Public Class TradeListSorter
        Implements IComparer(Of Trade)

        Public Function Compare(ByVal x As Trade, ByVal y As Trade) As Integer Implements System.Collections.Generic.IComparer(Of Trade).Compare
            Return String.Compare(x.Name, y.Name)
        End Function

    End Class

    Public Function ReadTradeList() As List(Of Trade)
        'Read the trade in your file name format of choice.
        Dim Trades As New List(Of Trade)
        Dim FileStream As New IO.FileStream("TradeList.txt", IO.FileMode.Open)
        Dim StreamReader As New IO.StreamReader(FileStream)
        Dim TradeLine As String()
        Dim Seperater As Char() = {","c}

        Try

            Do While StreamReader.Peek <> -1
                TradeLine = StreamReader.ReadLine.Split(Seperater, StringSplitOptions.RemoveEmptyEntries)

                'validate.  Sold seperately

                Trades.Add(New Trade(CStr(TradeLine(0)), CSng(TradeLine(1))))
            Loop

        Catch ex As Exception
            'handle error
        Finally
            FileStream.Dispose()
            StreamReader.Dispose()
        End Try

        'Sort by name and Return
        Trades.Sort(New TradeListSorter)
        Return Trades

    End Function

    Public Function ReadTradeTable() As DataTable
        'Read the trade in your file name format of choice.
        Dim TradeTable As New DataTable
        Dim Row As DataRow
        Dim FileStream As New IO.FileStream("TradeList.txt", IO.FileMode.Open)
        Dim StreamReader As New IO.StreamReader(FileStream)
        Dim TradeLine As String()
        Dim Seperater As Char() = {","c}

        TradeTable.TableName = "Trades"
        TradeTable.Columns.Add("Name", GetType(String))
        TradeTable.Columns.Add("Cost", GetType(Single))

        'example how you can set defaults.
        TradeTable.Columns("Name").DefaultValue = "Trade"
        TradeTable.Columns("Name").AllowDBNull = False

        TradeTable.Columns("Cost").DefaultValue = 0
        TradeTable.Columns("Cost").AllowDBNull = False

        Try

            Do While StreamReader.Peek <> -1
                TradeLine = StreamReader.ReadLine.Split(Seperater, StringSplitOptions.RemoveEmptyEntries)

                'validate.  Sold seperately

                Row = TradeTable.NewRow()
                Row("Name") = TradeLine(0)
                Row("Cost") = CSng(TradeLine(1))
                TradeTable.Rows.Add(Row)
            Loop

        Catch ex As Exception
            'handle error
        Finally
            FileStream.Dispose()
            StreamReader.Dispose()
        End Try

        Return TradeTable
    End Function

    Public Function WriteTradeList(ByVal trades As List(Of Trade)) As Boolean
        'Write the file in your file name and format of choice.
        Dim FileStream As New IO.FileStream("TradeList.txt", IO.FileMode.Create)
        Dim StreamWriter As New IO.StreamWriter(FileStream)

        Try
            For Each Trade As Trade In trades
                StreamWriter.WriteLine(Trade.Name & "," & CStr(Trade.Cost))
            Next
            StreamWriter.Flush()
            Return True
        Catch ex As Exception
            'handle error
        Finally
            StreamWriter.Dispose()
            FileStream.Dispose()
        End Try

    End Function

    Public Function WriteTradeList(ByVal trades As DataTable) As Boolean
        'Write the file in your file name and format of choice.
        'Writes the data from a table
        Dim FileStream As New IO.FileStream("TradeList.txt", IO.FileMode.Create)
        Dim StreamWriter As New IO.StreamWriter(FileStream)

        Try
            For Each Row As DataRow In trades.Rows
                StreamWriter.WriteLine(Row("Name") & "," & CStr(Row("Cost")))
            Next
            StreamWriter.Flush()
            Return True
        Catch ex As Exception
            'handle error
        Finally
            StreamWriter.Dispose()
            FileStream.Dispose()
        End Try

    End Function

End Module
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.