VB.NET XML and DataGridView

Tekno Venus

Senior Administrator, Developer
Staff member
Joined
Jul 21, 2012
Posts
7,274
Location
UK
Hello fellow programmers!

I will note that this is part of an assignment, so I don't want you to give me the answer outright, I just need some hints to help me find the solution. All advice is welcome!

So, as part of the project, I must create a program that can save and store ingredients for different recipes in VB.NET. For the data storage, I would like to use XML files because I feel that it is an efficient way to do so, but please suggest an alternative if you feel one is suitable.

So, the XML file I am testing with is as follows:

Code:
<?xml version="1.0" standalone="yes"?>
<UserRecipes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <recipe name="Chocolate" portions="5">
    <ingredient quantity="500" unit="g">Chocolate Bar</ingredient>
    <ingredient quantity="300" unit="g">Chocolate Buttons</ingredient>
    <ingredient quantity="250" unit="g">Hot Chocolate</ingredient>
  </recipe>
  <recipe name="Cookies" portions="24">
    <ingredient quantity="4" unit="oz">Flour</ingredient>
    <ingredient quantity="200" unit="g">Chocolate Buttons</ingredient>
    <ingredient quantity="600" unit="g">Sugar</ingredient>
  </recipe>
  <recipe name="Cake" portions="22">
    <ingredient quantity="4" unit="oz">Flour</ingredient>
    <ingredient quantity="4" unit="oz">Sugar</ingredient>
    <ingredient quantity="4" unit="oz">Butter</ingredient>
    <ingredient quantity="60" unit="n/a">Eggs</ingredient>
  </recipe>
</UserRecipes>

You can see that I have multiple recipes and the ingredients as child tags.

My form currently looks like this:

Screenshot - 12_12_2013 , 05_27_35 PM.png

The program consists of a dropdown box for the user to select recipes, a DatGridView control to view/edit the ingredients, an up/down selection box to allow them to enter portion amounts (along with a checkbox that when checked, will scale up the quantities in the ingredients according to the new amount of people selected).

Currently, I have a way to view all the recipes in combobox, and can view either all the ingredients in the XML file in the DataGridView, or all the recipe names/portions in the DataGridView.

I need a way to filter the selected ingredients to only show the ones related to the one selected in the drop down.

My current code is below. Please note, this is no where near finished, but just used so I can get an idea of the techniques I need to use before I create the final program in school.

Code:
Imports System.IO
Imports System.Xml
Public Class Form1
    Public xmld As XmlDocument
    Public nodelist As XmlNodeList
    Public DS As New DataSet
    Public DS2 As New DataSet

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        xmld = New XmlDocument()
        xmld.Load("G:\Computing\!Recipe Test\XMLTest.xml")
        nodelist = xmld.SelectNodes("/UserRecipes/recipe")
        For Each node In nodelist
            Dim recipeName = node.Attributes.GetNamedItem("name").Value
            ComboBox1.Items.Add(recipeName)
        Next
        Dim xmlFile = XmlReader.Create("G:\Computing\!Recipe Test\XMLTest.xml", New XmlReaderSettings())
        DS.ReadXml(xmlFile, XmlReadMode.Auto)
        Dim dvRecipes As DataView = DS.Tables(0).DefaultView
        DataGridView1.DataSource = dvRecipes
        xmlFile.Close()
    End Sub

    Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
        Dim dvRecipes As DataView = DS.Tables(0).DefaultView
        dvRecipes.RowFilter = "name='" & ComboBox1.Text & "'"
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        DS.WriteXml("G:\Computing\!Recipe Test\XMLTest.xml")
    End Sub
End Class

My changing the index in this line from 0 to 1:
Code:
Dim dvRecipes As DataView = DS.Tables(0).DefaultView
I can either view all the recipe names, or all the ingredients for all the recipes.

I've hit a brick wall with this, and need all the help I can get.

Many, many thanks!

Stephen
 
The data doesn't look like anything complex, I would've chosen a Serialization method for the data instead. I wrote an example of LINQ to XML as well someplace, which would allow you to choose and filter that way, otherwise iterating through the nodes and checking the ones you want to filter out, or only checking for the ones that pertain to the ones you want to retrieve is still pretty easy. In that loop just check the node's properties for what you want to filter.

Here's my LINQ to XML example as well if you're interested: LINQ to XML Full Example
And a SOAP Serialization class I wrote: SOAP Format Serialization/Deserialization - Class Object (NOTE: Read Post #4)
 
Last edited:
Thanks Ace.

Well, I now have a way of doing it, but it's very rudimentary right now. The problem I currently have is saving this - I have no idea how to go about this correctly.

I feel I may be doing this wrong, and have looked into serialisation and LINQ, but got even more confused!

Current Code:

Code:
Imports System.IO
Imports System.Xml

Public Class Form1
    Public xmld As XmlDocument
    Public nodelist As XmlNodeList
    Public DS As New DataSet
    Dim newTable As New DataTable

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        xmld = New XmlDocument()
        xmld.Load("C:\Users\Stephen\Desktop\XMLTest.xml")
        nodelist = xmld.SelectNodes("/UserRecipes/recipe")
        For Each node In nodelist
            ComboBox1.Items.Add(node.Attributes.GetNamedItem("name").Value)
        Next
        newTable.Columns.Add("Ingredient")
        newTable.Columns.Add("Quantity")
        newTable.Columns.Add("Unit")
    End Sub

    Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
        newTable.Clear()
        Dim selectedNode = xmld.SelectSingleNode("/UserRecipes/recipe[@name='" & ComboBox1.Text & "']")
        Dim amount As Integer = selectedNode.ChildNodes.Count
        For i As Integer = 0 To amount - 1
            newTable.Rows.Add(selectedNode.ChildNodes(i).InnerText, selectedNode.ChildNodes(i).Attributes("quantity").Value, selectedNode.ChildNodes(i).Attributes("unit").Value)
        Next
        DataGridView1.DataSource = newTable
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        newTable.TableName = "UserRecipies"
        newTable.WriteXml("C:\Users\Stephen\Desktop\XMLTest.xml")
    End Sub
End Class

Again, any help appreciated!! Saving is currently the issue!

Stephen
 
Last edited by a moderator:
Serialization just makes the process of saving and reading back the data much easier if you can understand it. No fiddling around, it just does what it is meant to do, so long as you understand the differences between serialization methods, and their limitations so that you can adjust things accordingly. LINQ is not really needed, and is probably less useful than just iterating and enumerating the data as you go along, but it makes the code shorter, and this is still a possibility with LINQ, which is why I posted it. The advantageous part about LINQ for this is you can recognize the data as a query-able dataset, and grab, as well as create new data formats from that query.

I'll try my best to look at your code later tomorrow if I can.
 
<pedant mode>
Dunno about the programming, but you're mixing units - and that's always a red flag!
If you're going to use 'g', then don't use 'oz'!
Apart from anything else, whatever the output, it's going to be very confusing later, as you add more data and print out recipes.

Stick to one system or the other :)

</pedant mode>

other than that - have fun!
 

Has Sysnative Forums helped you? Please consider donating to help us support the site!

Back
Top