I have created a program where a user can input a recipe, and then press a button and this will then be written to a file. On the other side of the interface, the user can select this previously saved recipe and the contents will be read from this Notepad file.

I am now trying to create a code that allows the user to recalculate the quantities but I need a substring. When read from the file, the listbox is filled with something like the following:

150, Flour, Grams
150, Sugar, Grams

Is there any way to do this?

If you need more information then just ask, sorry if it's all a bit mixed up.

Thanks in advance :)

Do you have to use Notepad /text files as your storage medium? It seams to me it would be a lot quicker and more efficient to use a database to store the recipes and then out put this data to text file - you would be able to do the calculation of quantities as you output to the file too.

Off the top of my head, you could have a recipe table containing the instructions and quantity produced. Then maybe an ingredients table linked back to the recipe where you could specify item name, quantity and unit of measurement. Then if your base recipe is to say produce a 200 gram cup cake and the user wants to make a 600 gram cake you can multiply each items quantity value by 3 to get three times as much.

commented: Great idea! +6

Create a list of string and cycle through them:

'Where sr is a stream reader
Dim lstIngredients As List(Of String) = sr.ReadLine().Split(",").ToList

'lstIngredients(0) = 150
'lstIngredients(1) = Flour
'lstIngredients(2) = Grams

the conversion from string to double is not valid?

Are you programming with option strict on?

I am not able to use a database because reading and writing from files is a requirment.

no i have option explicit on

Can you post the part of the code that is throwing the error?

Or is it throwing the error on the first string read in?

I am bored and decided to go into a tutor mode. :)

First off I believe in strongly typed data, so I recommend that you use an Ingredient class.

Public Class Ingredient
   ''' <summary>
   ''' Builds a new ingredient from a comma delimited source string 
   ''' </summary>
   ''' <param name="Source">ex: "150, Flour, Grams"</param>
   Public Sub New(ByVal Source As String)
      ' split the string into its parts
      Dim parts() As String = Source.Split(",".ToCharArray, StringSplitOptions.RemoveEmptyEntries)

      If parts.Length <> 3 Then 'there should only be 3 parts
         Throw New ArgumentException("Invalid source string:  " & Source)
      End If
         _Quantity = CSng(parts(0)) 'convert string to single
      Catch ex As Exception
         Throw New ArgumentException("Invalid source string quanity:  " & parts(0))
      End Try
      _Name = parts(1)
      _Units = parts(2)
   End Sub

   Private _Quantity As Single
   Public Property Quantity() As Single
         Return _Quantity
      End Get
      Set(ByVal value As Single)
         _Quantity = value
      End Set
   End Property 'Quantity

   Private _Name As String
   Public Property Name() As String
         Return _Name
      End Get
      Set(ByVal value As String)
         _Name = value
      End Set
   End Property 'Name

   Private _Units As String
   Public Property Units() As String
         Return _Units
      End Get
      Set(ByVal value As String)
         _Units = value
      End Set
   End Property 'Units

   ' This will be called by the listbox to provide a string reprepresentation of the the ingredient
   Public Overrides Function ToString() As String
      Return String.Format("{0}, {1}, {2}", _Quantity.ToString, _Name, _Units)
   End Function

End Class

Now to make use of the class. First create a create a BindingList(Of Ingredient) hold your ingredients. This will act as the data source for the listbox.

   ' create a BindingList(Of Ingredient) hold your ingredients
   Dim blIngredients As New System.ComponentModel.BindingList(Of Ingredient)

   Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
      ListBox1.DataSource = blIngredients 'tell the ListBox to display this list
   End Sub

To load your recipe file:

   Private Sub LoadRecipe(ByVal fn As String)
      ' Load blIngredients
      blIngredients.Clear() 'clears the list items
      Dim s As IO.Stream = IO.File.OpenRead(fn)
      Dim sr As New IO.StreamReader(s)
      Do While sr.Peek <> -1
        blIngredients.Add(New Ingredient(sr.ReadLine()))
   End Sub

Now an example of adjusting the quantities. As we have used strongly typed data, each item in the list is an ingredient type with a quantity that can be manipulated arithmetically since it is stored a "Single" type.

   Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
      ' Double the quantities

      For i As Int32 = 0 To blIngredients.Count - 1
         blIngredients.Item(i).Quantity *= 2
         blIngredients.ResetItem(i) ' this is needed to update the ListBox Display
   End Sub

Now how to write this modified list back to a file.

   Private Sub SaveRecipe(ByVal fn As String)
      ' Load blIngredients
      Dim s As IO.Stream = IO.File.Create(fn)
      Dim sw As New IO.StreamWriter(s)
      For i As Int32 = 0 To blIngredients.Count - 1
   End Sub
commented: Great post! But you just did their homework for them. +6


Private Sub ButtonOkServed_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOKServed.Click
        lstExistingRecipe.Items.Clear() 'clear all in the listbox
        Dim FileReader As New IO.StreamReader("E:\RecipeFiles\" & lstRecipeChoose.Text & ".txt")    'read recipe from file
        Dim lstIngredients As List(Of String) = FileReader.ReadLine().Split(",").ToList
        'lstIngredients(0) = 150
        'lstIngredients(1) = Flour
        'lstIngredients(2) = Grams
        Quantity = Quantity / txtCurrentServings.Text * txtNewNumberServed.Text
        NewRecipe = Quantity & NewIngredientsAndUnits           'new recipe puts substrings back together
        lstExistingRecipe.Items.Add(NewRecipe)                  'output the new recipe in place of the old one in the listbox
    End Sub

this is where it goes wrong

TnTinMN: thank you for your detailed reply, i will try the code tomorrow and i will get back to you. :)

On a related note, have you considered that recipes don't "scale up" easily when it comes to things like cooking times?

I haven't included the cooking times, thanks anyway!