Home

Operations on XML Elements

Editing an XML Element

Introduction

In some cases, you may want to perform an operation on an existing and particular node. For example, you may want to change the value of a node, you may want to add a new child node to an existing node, etc. Before taking any of these actions, you must be able to locate or identify the desired element.

Locating an element consists of looking for a particular node among the nodes. To do this, you must start somewhere. Obviously, the first node you can identify is the root. Once you get the root, you can then get a collection of its children. After getting a collection of the children of the root, you can locate a node in the collection. If the node you are looking for is a child of that first collection, you can then get a collection of the child nodes of that node and proceed.

The System.Xml namespace provides various means of looking for a node in an XML file.

Locating an Element Using its Index

Consider the following XML file named videos.xml:

<?xml version="1.0" encoding="utf-8"?>
<videos>
  <video>
	<title>The Distinguished Gentleman</title>
	<director>Jonathan Lynn</director>
	<length>112 Minutes</length>
	<format>DVD</format>
	<rating>R</rating>
  </video>
  <video>
	<title>Her Alibi</title>
	<director>Bruce Beresford</director>
	<length>94 Minutes</length>
	<format>DVD</format>
	<rating>PG-13</rating>
  </video>
  <video>
	<title>The Day After Tomorrow</title>
	<director>Roland Emmerich</director>
	<length>124 Minutes</length>
	<format>DVD</format>
	<rating>PG-13</rating>
  </video>
  <video>
	<title>Other People&#039;s Money</title>
	<director>Alan Brunstein</director>
	<length>114 Minutes</length>
	<format>VHS</format>
	<rating>PG-13</rating>
  </video>
</videos>

We know that the XmlNodeList class is equipped with both a method and an indexed propery named Item. Their syntaxes are:

public abstract XmlNode Item(int index);
public virtual XmlNode this[int i] { get; }

These two members allow you to access an element based on its index. Here are examples:

using System;
using System.IO;
using System.Xml;
using System.Windows.Forms;

namespace VideosCollection
{
    public partial class Form1 : Form
    {
        public Form1() => InitializeComponent();

        private void btnVideosCollection_Click(object sender, EventArgs e)
        {
            string strVideosFile = @"C:\Videos Collection\Videos.xml";
            XmlDocument xdVideos = new XmlDocument();

            if (File.Exists(strVideosFile))
            {
                xdVideos.Load(strVideosFile);

                XmlElement xeRoot = xdVideos.DocumentElement;
                XmlNodeList xnlVideos = xeRoot.ChildNodes;

                MessageBox.Show(xnlVideos[1].InnerText, "Video Collecton");
                MessageBox.Show(xnlVideos.Item(3).InnerXml, "Video Collecton");
            }
        }
    }
}

This would produce:

Locating an Element Using its Index

Locating an Element Using its Index

You can use this characteristic to locate a node. Because XML is very flexible with the names (you can have two child nodes that have the same name) and values (you can have two child nodes that have the same value) of nodes, when creating an XML file, it is your responsibility to create a scheme that would eventually allow you to uniquely identify each element.

Locating an Element Using its Name

To assist you with locating the first child node of a node, the XmlNode class is equipped with an indexed property (named Item) overloaded with two versions. One of the versions is declared as follows:

public virtual XmlElement this[string name] { get; }

This indexed property takes the name of a node as argument. After the property has been called, the parser checks the child nodes of the element on which the property was applied. If the parser finds a node with that name, it returns it as an XmlElement object. Here is an example:

using System;
using System.IO;
using System.Xml;
using System.Windows.Forms;

namespace VideosCollection
{
    public partial class Form1 : Form
    {
        public Form1() => InitializeComponent();

        private void btnVideosCollection_Click(object sender, EventArgs e)
        {
            XmlDocument xdVideos = new XmlDocument();
            FileInfo fiVideos = new FileInfo(@"C:\Videos Collection\Videos.xml");

            if( fiVideos.Exists == true )
            {
                xdVideos.Load(fiVideos.FullName);

                XmlElement xeRoot     = xdVideos.DocumentElement;
                XmlNodeList xnlVideos = xeRoot.ChildNodes;

                MessageBox.Show(xnlVideos[1]["director"].InnerText, "Video Collection");
                MessageBox.Show(xnlVideos.Item(3)["format"].InnerXml, "Video Collection");
            }
        }
    }
}

Based on the videos.xml file we had earlier, this would produce:

Locating an Element Using its Name

Locating an Element Using its Name

If the node has more than one child with the same name, then it would return the first child with that name. You can use this characteristic to look for, or locate, an element.

Locating an Element Using a Tag Name

To assist you with finding a node, the XmlDocument class is equipped with a method name GetElementByTagName which is overloaded with two versions. One of the syntaxes used is:

public virtual XmlNodeList GetElementsByTagName(string name);

This method takes as argument a string. The string must be the name of a node. If at least one node that holds that name exists in the file, this method returns a collection of the nodes with that name. If there is no node with that name, the collection is returned empty and there is no exception thrown.

Here is an example of calling the method:

using System;
using System.IO;
using System.Xml;
using System.Windows.Forms;

namespace VideosCollection
{
    public partial class Form1 : Form
    {
        public Form1() => InitializeComponent();

        private void btnVideosCollection_Click(object sender, EventArgs e)
        {
            XmlDocument xdVideos = new XmlDocument();
            string strVideosFile = @"C:\Videos Collection\Videos.xml";

            if (File.Exists(strVideosFile))
            {
                xdVideos.Load(strVideosFile);

                // Get a reference to the root node
                XmlElement xeRoot = xdVideos.DocumentElement;

                // Create a list of nodes whose name is Title
                XmlNodeList xnlTitles = xdVideos.GetElementsByTagName("title");

                foreach (XmlNode node in xnlTitles)
                    MessageBox.Show(string.Format("Inner Text: {0}", node.InnerText), "Video Collection");
            }
        }
    }
}

This would produce:

Locating an Element Using a Tag Name

Locating an Element Using a Tag Name

Locating an Element Using a Tag Name

Locating an Element Using a Tag Name

Once you have a list of the nodes of a particular criterion, you can then act as you see fit. For example, you can look for a particular node that holds text of your choice.

Updating an Element

Consider the following version of our Videos.xml file:

<?xml version="1.0" encoding="utf-8"?>
<videos>
  <video>
    <title>Her Alibi</title>
    <director>Bruce Beresford</director>
    <length>94 Minutes</length>
    <format>DVD</format>
    <rating>PG-13</rating>
  </video>
  <video>
    <title>The Day After Tomorrow</title>
    <director>Roland Emmerich</director>
    <length>124 Minutes</length>
    <format>DVD</format>
    <rating>PG-13</rating>
  </video>
</videos>

The .NET Framework implementation of XML provides various options to change the aspect, structure, or value(s), of an element. For example, you can use the same logic used in collection classes. This consists of locating a node and simply changing its value(s). Here is an example:

using System.Xml;

public class Exercise
{
    public static int Main(string[] args)
    {
        string strVideosFile = @"C:\Videos Collection\Videos.xml";
        XmlDocument xdVideos = new XmlDocument();

        // Open the XML file
        xdVideos.Load(strVideosFile);
        XmlNodeList xnlVideos = xdVideos.DocumentElement.GetElementsByTagName("title");

        foreach (XmlNode xnVideo in xnlVideos)
        {
            if (xnVideo.InnerText.Contains("The Day After Tomorrow"))
            {
                xnVideo.ParentNode.InnerXml = "<title>Day After Tomorrow (The)</title>" +
                                              "<director>Roland Emmerich</director>" +
                                              "<year>2004</year>" +
                                              "<length>124 Minutes</length>" +
                                              "<format>DVD</format>" +
                                              "<rating>PG-13</rating>";
                                              
                xdVideos.Save(strVideosFile);
                break;
            }
        }

        return 10_101;
    }
}

This would produce:

<?xml version="1.0" encoding="utf-8"?>
<videos>
  <video>
    <title>Her Alibi</title>
    <director>Bruce Beresford</director>
    <length>94 Minutes</length>
    <format>DVD</format>
    <rating>PG-13</rating>
  </video>
  <video>
    <title>Day After Tomorrow(The)</title>
    <director>Roland Emmerich</director>
    <year>2004</year>
    <length>124</length>
    <format>DVD</format>
    <rating>PG-13</rating>
  </video>
</videos>

On the other hand, the XmlNode class is equipped with a method named ReplaceChild. Its syntax is:

public virtual XmlNode ReplaceChild(XmlNode newChild, XmlNode oldChild);

To use this method, first locate an element and get its reference. Then change the values or child nodes you want, and finally replace the original value with the new version. In reality, and as its name implies, it is not the primary purpose of this method to edit or update an element. The role of this method is to use one node in place of another.

Deleting Elements

Deleting an Element

If you have a node you don't want or don't need anymore in the document, you can delete it. To let you delete a node, the XmlNode class is equipped with a method named RemoveChild. Its syntax is:

public virtual XmlNode RemoveChild(XmlNode oldChild);

This method takes as argument the node to delete. If the node exists, it would be deleted and the method would return the node that was deleted. If the node does not exist, nothing would happen. To effectively use this method, you should first locate the particular node you want to delete. You can look for it using any of the techniques we have applied so far. Once you find the node, you can then delete it. Imagine you want to delete a node whose name is Director and whose value is Bruce Beresford. Here is an example of calling this method to perform the operation:

using System.IO;
using System.Xml;

public class Exercise
{
    public static int Main(string[] args)
    {
        string strVideosFile = @"C:\Videos Collection\Videos.xml";
        XmlDocument xdVideos = new XmlDocument();

        if (File.Exists(strVideosFile))
        {
            xdVideos.Load(strVideosFile);

            // Get a reference to the root node
            XmlElement xeRoot = xdVideos.DocumentElement;

            // Create a list of the videos
            XmlNodeList xnlVideos = xdVideos.GetElementsByTagName("video");

            // visit each video
            foreach (XmlNode node in xnlVideos)
            {
                // Within a video, get a list of its children
                XmlNodeList xnlChildren = node.ChildNodes;

                // Visit each child node
                foreach (XmlNode dir in xnlChildren)
                {
                    // If the child node is Bruce Beresford
                    if (dir.InnerText == "Bruce Beresford")
                    {
                        node.RemoveChild(dir);

                        // Save the file
                        xdVideos.Save(strVideosFile);

                        // Stop
                        break;
                    }
                }
            }
        }

        return 20_2020;
    }
}

Clearing an Element of its Children

To let you delete all child nodes of a node, the XmlNode class provides a method named RemoveAll. Its syntax is:

public virtual void RemoveAll();

When called, this method will remove all child nodes, if any, of their parent node. Here is an example of calling it:

using System.IO;
using System.Xml;

public class Exercise
{
    public static int Main(string[] args)
    {
        string strVideosFile = @"C:\Videos Collection\Videos.xml";
        XmlDocument xdVideos = new XmlDocument();

        if (File.Exists(strVideosFile))
        {
            // Open the XML file
            xdVideos.Load(strVideosFile);
            // Clear the XML document
            xdVideos.DocumentElement.RemoveAll();
            // Save the XML document
            xdVideos.Save(strVideosFile);
        }

        return 353_454;
    }
}

This would produce:

<?xml version="1.0" encoding="utf-8"?>
<videos>
</videos>

Practical LearningPractical Learning: Creating the Water Distribution Company Application

  1. Start Microsoft Visual Studio and create a Windows Forms application named WaterDistributionCompany1
  2. To create a new file, on the main menu, click Project -> Add New Item...
  3. In the left list under Visual C# Items, click Data and, in the middle list, click Xml File
  4. Change the file name to WaterMeters
  5. Click Add
  6. Change the document as follows:
    <?xml version="1.0" encoding="utf-8" ?>
    <water-meters>
    	<water-meter>
    		<meter-number>392-44-572</meter-number>
    		<make>Constance Technologies</make>
    		<model>TG-4822</model>
    		<meter-size>5/8 Inches</meter-size>
    	</water-meter>
    	<water-meter>
    		<meter-number>938-75-869</meter-number>
    		<make>Stanford Trend</make>
    		<model>266G</model>
    		<meter-size>1 1/2 Inches</meter-size>
    	</water-meter>
    	<water-meter>
    		<meter-number>799-28-461</meter-number>
    		<make>Constance Technologies</make>
    		<model>BD-7000</model>
    		<meter-size>3/4 Inches</meter-size>
    	</water-meter>
    	<water-meter>
    		<meter-number>207-94-835</meter-number>
    		<make>Constance Technologies</make>
    		<model>TG-6220</model>
    		<meter-size>5/8 Inches</meter-size>
    	</water-meter>
    	<water-meter>
    		<meter-number>592-84-957</meter-number>
    		<make>Standard Trend</make>
    		<model>428T</model>
    		<meter-size>1 Inch3/4 Inches</meter-size>
    	</water-meter>
    	<water-meter>
    		<meter-number>374-06-284</meter-number>
    		<make>Raynes Energica</make>
    		<model>i2022</model>
    		<meter-size>3/4 Inches</meter-size>
    	</water-meter>
    </water-meters>
  7. In the Solution Explorer, right-click WaterDistributionCompany1 -> Add -> Form (Windows Forms)...
  8. Change the file name to WaterMeters as the name of the form
  9. Click Add
  10. Design the form as follows:

    Introduction to XML

    Control (Name) Text Other Properties
    ListView lvwWaterMeters  
    FullRowSelect: True
    GridLines:     True
    Anchor:		 Top, Bottom, Left, Right
    Button btnClose Close Anchor: Bottom, Right

    List View Columns

    (Name) Text TextAlign Width
    colNumber #   20
    colMeterNumber Meter Number Center 80
    colMake Make   110
    colModel Model   80
    colMeterSize Meter Size Center 80
  11. Double-click an unoccupied area of the form to launch its Load event
  12. Return to the form and double-click the Close button
  13. Change the document as follows:
    using System;
    using System.IO;
    using System.Xml;
    using System.Windows.Forms;
    
    namespace WaterDistributionCompany1
    {
        public partial class WaterMeters : Form
        {
            public WaterMeters()
            {
                InitializeComponent();
            }
    
            private void WaterMeters_Load(object sender, EventArgs e)
            {
                // Create a DOM object that will give access to the XML
                XmlDocument xdWaterMeters = new XmlDocument();
                // Specify the name of the file that contains the water meters records
                string strWaterMeters = "../../WaterMeters.xml";
    
                // Find out whether a file for water meters was already created.
                if (File.Exists(strWaterMeters))
                {
                    // If that file exists, create a file stream to hold the file, and open it
                    using (FileStream fsWaterMeters = new FileStream(strWaterMeters, FileMode.Open,
                                                                     FileAccess.Read, FileShare.Read))
                    {
                        // Load the XML elements from the file to the DOM object
                        xdWaterMeters.Load(fsWaterMeters);
                        // Get a collection of the XML elements from the DOM object
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement.ChildNodes;
    
                        // This small integer will simpoly be used to count the number of water meters
                        int i = 1;
    
                        // Just in case the list view was displaying something, remove those things
                        lvwWaterMeters.Items.Clear();
    
                        // Visit each record from the collection of water meters
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            /* Create list view item. Get it ready to display the 
                             * ordered number of the water meter. The number starts at 1. */
                            ListViewItem lviWaterMeter = new ListViewItem(i.ToString());
    
                            /* Create each child node from each water meter record and add it as a child 
                             * of the list view item (so it can be displayed in the appropriate colum). */
                            lviWaterMeter.SubItems.Add(xnWaterMeter.FirstChild.InnerText);
                            lviWaterMeter.SubItems.Add(xnWaterMeter.FirstChild.NextSibling.InnerText);
                            lviWaterMeter.SubItems.Add(xnWaterMeter.FirstChild.NextSibling.NextSibling.InnerText);
                            lviWaterMeter.SubItems.Add(xnWaterMeter.FirstChild.NextSibling.NextSibling.NextSibling.InnerText);
    
                            // Add the list view item to the list view (so it can be displayed in the appropriate colum).
                            lvwWaterMeters.Items.Add(lviWaterMeter);
                            // Increase the counter of the water meters
                            i++;
                        }
                    } // Close the stream
                }
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                // Close the form
                this.Close();
            }
        }
    }
  14. To create a new form, in the Solution Explorer, right-click WaterDistributionCompany1 -> Add -> Form (Windows Forms)...
  15. Change the file Name to CustomerNew
  16. Click Add
  17. Design the form as follows:

    Introducing XML Nodes

    Control (Name) Text
    Label   Account #:
    TextBox txtAccountNumber  
    Label   Meter #:
    TextBox txtMeterNumber  
    Label   Meter Details:
    TextBox txtMeterDetails  
    Label   First Name:
    TextBox txtFirstName  
    Label   Last Name:
    TextBox txtLastName  
    Label   Address:
    TextBox txtAddress  
    Label   City:
    TextBox txtCity  
    Label   County:
    TextBox txtCounty  
    Label   State:
    TextBox txtState  
    Label   ZIP Code:
    TextBox txtZIPCode  
    Button btnSave Save
    Button btnClose Close
  18. On the form, click the Meter # text box
  19. In the Properties window, click the Events button Events
  20. Double-click Leave
  21. Return to the form and double-click the Save button
  22. Return to the form and double-click the Close button
  23. Change the document as follows:
    using System;
    using System.IO;
    using System.Xml;
    using System.Windows.Forms;
    
    namespace WaterDistributionCompany1
    {
        public partial class CustomerNew : Form
        {
            public CustomerNew()
            {
                InitializeComponent();
            }
    
            private void txtMeterNumber_Leave(object sender, EventArgs e)
            {
                XmlDocument xdWaterMeters = new XmlDocument();
                string strFileWaterMeters = "../../WaterMeters.xml";
    
                // The user must provide a valid meter number.
                // To start, find out if a file for water meters was created already.
                if (File.Exists(strFileWaterMeters))
                {
                    // If a file for water meters exists, open it
                    using (FileStream fsWaterMeters = new FileStream(strFileWaterMeters, FileMode.Open,
                                                                     FileAccess.Read, FileShare.Read))
                    {
                        // Store the list of water meters in an XML document
                        xdWaterMeters.Load(fsWaterMeters);
    
                        // Create a list of child nodes of the root node
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement.ChildNodes;
    
                        // Visit each node of the list of elements
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            // When you get to a list of nodes, create a list of its children and visit each
                            foreach (XmlNode xnMeterNumber in xnWaterMeter.ChildNodes)
                            {
                                // If you find a meter number that is the same as the meter number from the form, ...
                                if (xnMeterNumber.InnerText == txtMeterNumber.Text)
                                {
                                    // ... display its details
                                    txtMeterDetails.Text = xnMeterNumber.NextSibling.InnerText + " " +
                                                           xnMeterNumber.NextSibling.NextSibling.InnerText + 
                                                           " (Meter #: " + txtMeterNumber.Text + ")";
                                }
                            }
                        }
                    }
                }
            }
    
            private void btnSaveCustomer_Click(object sender, EventArgs e)
            {
                // If the user didn't provide an account number, don't proceed any further
                if (string.IsNullOrEmpty(txtAccountNumber.Text))
                {
                    MessageBox.Show("You must enter a new unique account number of the customer.",
                                    "Water Distribution Company");
                    return;
                }
    
                // If the user didn't provide an account number, ...
                if (string.IsNullOrEmpty(txtMeterNumber.Text))
                {
                    MessageBox.Show("You must provide a valid meter number.",
                                    "Water Distribution Company");
                    return;
                }
    
                XmlDocument xdCustomersAccounts = new XmlDocument();
                string strCustomers = "../../Customers.xml";
    
                // It appears that the user provided both an account number and a valid meter number.
                // If an XML file for customers accounts was previously created, ...
                if (File.Exists(strCustomers))
                {
                    // ... open it ...
                    using (FileStream fsCustomers = new FileStream(strCustomers, FileMode.OpenOrCreate,
                                                                   FileAccess.ReadWrite, FileShare.ReadWrite))
                    {
                        // ... and put the records in the DOM
                        xdCustomersAccounts.Load(fsCustomers);
                    }
                }
                else
                {
                    // If there no XML file yet for the customers, create skeleton code for an XML document
                    xdCustomersAccounts.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                                                "<customers></customers>");
                }
    
                // Get ready to create an XML element named customer
                XmlElement xeCustomer = xdCustomersAccounts.CreateElement("customer");
    
                // Create the markup of the XML customer
                string strCustomer = "<account-number>" + txtAccountNumber.Text + "</account-number>" +
                                     "<meter-number>"   + txtMeterNumber.Text   + "</meter-number>"   +
                                     "<first-name>"     + txtFirstName.Text     + "</first-name>"     +
                                     "<last-name>"      + txtLastName.Text      + "</last-name>"      +
                                     "<address>"        + txtAddress.Text       + "</address>"        +
                                     "<city>"           + txtCity.Text          + "</city>"           +
                                     "<county>"         + txtCounty.Text        + "</county>"         +
                                     "<state>"          + txtState.Text         + "</state>"          +
                                     "<zip-code>"       + txtZIPCode.Text       + "</zip-code>";
    
                // Specify the markup of the new element
                xeCustomer.InnerXml = strCustomer;
    
                // Add the new node to the root
                xdCustomersAccounts.DocumentElement.PrependChild(xeCustomer);
    
                // Save the (new version of the) XML file
                using (FileStream fsCustomers = new FileStream(strCustomers, FileMode.Create, FileAccess.Write, FileShare.Write))
                {
                    xdCustomersAccounts.Save(fsCustomers);
                }
    
                Close();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  24. To create a new form, in the Solution Explorer, right-click WaterDistributionCompany1 -> Add -> Form (Windows Forms)...
  25. Change the file name to CustomerEditor
  26. Click Add
  27. Design the form as follows:

    Using the Siblings of an XML Node

    Control (Name) Text
    Label   Account #:
    TextBox txtAccountNumber  
    Button btnOpen Open
    Label   Meter #:
    TextBox txtMeterNumber  
    Label   Meter Details:
    TextBox txtMeterDetails  
    Label   First Name:
    TextBox txtFirstName  
    Label   Last Name:
    TextBox txtLastName  
    Label   Address:
    TextBox txtAddress  
    Label   City:
    TextBox txtCity  
    Label   County:
    TextBox txtCounty  
    Label   State:
    TextBox txtState  
    Label   ZIP Code:
    TextBox txtZIPCode  
    Button btnUpdateWaterMeter Save/Update Water Meter
    Button btnClose Close
  28. In the Properties window, click the Events button Events
  29. On the form, click the Meter # text box
  30. Double-click Leave
  31. Return to the form and double-click the Open button
  32. Return to the form and double-click the Save/Update Water Meter button
  33. Return to the form and double-click the Close button
  34. Change the document as follows:
    using System;
    using System.IO;
    using System.Windows.Forms;
    using System.Xml;
    
    namespace WaterDistributionCompany1
    {
        public partial class CustomerEditor : Form
        {
            public CustomerEditor()
            {
                InitializeComponent();
            }
    
            void FindWaterMeter()
            {
                if( string.IsNullOrEmpty(txtMeterNumber.Text))
                    return;
    
                XmlDocument xdWaterMeters = new XmlDocument();
                string strFileWaterMeters = "../../WaterMeters.xml";
    
                /* This code will run if the user had first put a valid account number; then this 
                 * code is used to find the water meter associated with the customer's account. */
                if (File.Exists(strFileWaterMeters))
                {
                    // Open the file that contains the water meter details
                    using (FileStream fsWaterMeters = new FileStream(strFileWaterMeters, FileMode.Open,
                                                                     FileAccess.Read, FileShare.Read))
                    {
                        // Store the list of water meters in an XML DOM
                        xdWaterMeters.Load(fsWaterMeters);
    
                        // Create a list of elements based on a node named meter-number
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement.GetElementsByTagName("meter-number");
    
                        // Visit each node of the list of elements
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            // If you find a meter number that is the same as the meter number from the form, ...
                            if(xnWaterMeter.InnerText == txtMeterNumber.Text)   
                            {
                                // ... display its details
                                txtMeterDetails.Text = xnWaterMeter.NextSibling.InnerText + " " + xnWaterMeter.NextSibling.NextSibling.InnerText + " (Meter #: " + txtMeterNumber.Text + ")";
                            }
                        }
                    }
                }
            }
    
            private void txtMeterNumber_Leave(object sender, EventArgs e)
            {
                FindWaterMeter();
            }
    
            private void btnOpen_Click(object sender, EventArgs e)
            {
                XmlDocument xdCustomers = new XmlDocument();
                string strCustomers = "../../Customers.xml";
                FileInfo fiCustomers = new FileInfo(strCustomers);
    
                if( fiCustomers.Exists == true )
                {
                    using (FileStream fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open,
                                                                   FileAccess.Read, FileShare.Read))
                    {
                        xdCustomers.Load(fsCustomers);
    
                        XmlNodeList xnlCustomers = xdCustomers.DocumentElement.GetElementsByTagName("account-number");
    
                        foreach (XmlNode xnCustomer in xnlCustomers)
                        {
                            if( xnCustomer.InnerText == txtAccountNumber.Text)
                            {
                                txtMeterNumber.Text = xnCustomer.NextSibling.InnerText;
                                txtFirstName.Text   = xnCustomer.NextSibling.NextSibling.InnerText;
                                txtLastName.Text    = xnCustomer.NextSibling.NextSibling.NextSibling.InnerText;
                                txtAddress.Text     = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtCity.Text        = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtCounty.Text      = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtState.Text       = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtZIPCode.Text     = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
    
                                break;
                            }
                        }
                    }
                }
    
                FindWaterMeter();
            }
    
            private void btnSave_Click(object sender, EventArgs e)
            {
                if (string.IsNullOrEmpty(txtAccountNumber.Text))
                    return;
    
                if (string.IsNullOrEmpty(txtMeterNumber.Text))
                    return;
    
                XmlNode xnExisting = null;
    
                XmlDocument xdCustomers = new XmlDocument();
                string strCustomers = "../../Customers.xml";
                FileInfo fiCustomers = new FileInfo(strCustomers);
    
                if (fiCustomers.Exists == true)
                {
                    using (FileStream fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open,
                                                                   FileAccess.Read, FileShare.Read))
                    {
                        xdCustomers.Load(fsCustomers);
    
                        XmlNodeList xnlCustomers = xdCustomers.DocumentElement.ChildNodes;
    
                        foreach (XmlNode xnCustomer in xnlCustomers)
                        {
                            foreach (XmlNode xnAccountNumber in xnCustomer.ChildNodes)
                            {
                                if (xnAccountNumber.InnerText == txtAccountNumber.Text)
                                {
                                    xnExisting = xnCustomer;
                                    break;
                                }
                            }
                        }
                    }
                }
    
                XmlElement xeUpdatedCustomer = xdCustomers.CreateElement("customer");
                
                string strUpdatedCustomer = "<account-number>" + txtAccountNumber.Text + "</account-number>" +
                                            "<meter-number>" + txtMeterNumber.Text + "</meter-number>" +
                                            "<first-name>" + txtFirstName.Text + "</first-name>" +
                                            "<last-name>" + txtLastName.Text + "</last-name>" +
                                            "<address>" + txtAddress.Text + "</address>" +
                                            "<city>" + txtCity.Text + "</city>" +
                                            "<county>" + txtCounty.Text + "</county>" +
                                            "<state>" + txtState.Text + "</state>" +
                                            "<zip-code>" + txtZIPCode.Text + "</zip-code>";
                
                xeUpdatedCustomer.InnerXml = strUpdatedCustomer;
    
                xdCustomers.DocumentElement.ReplaceChild(xeUpdatedCustomer, xnExisting);
                
                using (FileStream fsCustomers = new FileStream(fiCustomers.FullName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
                {
                    xdCustomers.Save(fsCustomers);    
                }
                
                Close();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  35. To create another form, on the main menu, click Project -> Add New Form (Windows Forms)...
  36. Change the file name to Customers
  37. Click Add
  38. Design the form as follows:

    Using the Siblings of an XML Node

    Control (Name) Text Other Properties
    ListView lvwCustomers  
    FullRowSelect: True
    GridLines:     True
    Anchor:        Top, Bottom, Left, Right
    Button btnNewCustomer New Customer Anchor: Bottom, Right
    Button btnCustomerEditor Customer Editor... Anchor: Bottom, Right
    Button btnClose Close Anchor: Bottom, Right

    List View Columns

    (Name) Text TextAlign Width
    colNumber #   20
    colAccountNumber Account #   90
    colMeterNumber Meter Number Center 80
    colFirstName First Name   65
    colLastName Last Name   65
    colAddress Address   135
    colCity City   80
    colCounty County   80
    colZIPCode ZIP Code    
  39. Double-click an unoccupied area of the form to generate its Load event
  40. Return to the form and double-click the New Customer button
  41. Return to the form and double-click the Customer Editor button
  42. Return to the form and double-click the Close button
  43. Change the document as follows:
    using System;
    using System.IO;
    using System.Xml;
    using System.Windows.Forms;
    
    namespace WaterDistributionCompany1
    {
        public partial class Customers : Form
        {
            public Customers()
            {
                InitializeComponent();
            }
    
            private void Customers_Load(object sender, EventArgs e)
            {
                XmlDocument xdCustomers = new XmlDocument();
                string strCustomers = "../../Customers.xml";
                FileInfo fiCustomers = new FileInfo(strCustomers);
    
                if( File.Exists(strCustomers))
                {
                    // ... open that file
                    using( FileStream fsCustomers = new FileStream(strCustomers, FileMode.Open,
                                                                   FileAccess.Read, FileShare.Read) )
                    {
                        // Get the list of customers from the file and put that list in our initial empty list of customers
                        xdCustomers.Load(fsCustomers);
    
                        /* Since it appears that we currently have a list of customers, let's find out if
                         * it contains a customer with the account number that was entered in the form. */
                        XmlNodeList xnlCustomers = xdCustomers.DocumentElement.ChildNodes;
    
                        int i = 1;
    
                        lvwCustomers.Items.Clear();
    
                        // Visit each node of the list of elements
                        foreach (XmlNode xnCustomer in xnlCustomers)
                        {
                            ListViewItem lviCustomer = new ListViewItem(i.ToString());
    
                            lviCustomer.SubItems.Add(xnCustomer.FirstChild.InnerText);
                            lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling.InnerText);
                            lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling.NextSibling.InnerText);
                            lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling.NextSibling.NextSibling.InnerText);
                            lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.InnerText);
                            lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText);
                            lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText);
                            lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText);
    
                            lvwCustomers.Items.Add(lviCustomer);
                            i++;
                        }
                    } // Using
                }
            }
    
            private void btnNewCustomer_Click(object sender, EventArgs e)
            {
                CustomerNew cn = new CustomerNew();
    
                cn.ShowDialog();
    
                Customers_Load(sender, e);
            }
    
            private void btnCustomerEditor_Click(object sender, EventArgs e)
            {
                CustomerEditor ce = new CustomerEditor();
    
                ce.ShowDialog();
    
                Customers_Load(sender, e);
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  44. To create a new form, in the Solution Explorer, right-click WaterDistributionCompany -> Add -> Form (Windows Forms)...
  45. Change the file Name to BillPreparation
  46. Click Add
  47. To create a new form, on the main menu, click Project -> Add Form (Windows Forms)...
  48. Change the file name to BillEditor
  49. Click Add
  50. Click the BillPreparation.cs [Design] tab to return to the Bill Preparation form
  51. Design the form as follows:

    Using the Siblings of an XML Node

    Control (Name) Text Other Properties
    Label   Customer Account Information Font: Georgia, 9.75pt, style=Bold, Italic
    Label   Account #:  
    TextBox txtAccountNumber    
    Label   Customer Name:  
    TextBox txtCustomerName    
    TextBox txtAddress    
    TextBox txtCity    
    TextBox: txtCounty    
    TextBox txtState    
    TextBox txtZIPCode    
    Label   Meter Information Georgia, 9.75pt, style=Bold, Italic
    Label   Meter Details:  
    TextBox txtMeterNumber    
    TextBox txtMeterDetails    
    Label   Meter Reading  
    Label   ___________________  
    Label   Service Start Date:  
    DateTimeIcker dtpServiceStartDate   Format: Short
    Label   Service End Date:  
    DateTimeIcker dtpServiceEndDate   Format: Short
    Label   Number of Days:  
    TextBox txtNumberOfDays   TextAlign: Right
    Label   Counter Readiing Start:  
    TextBox txtCounterReadiingStart   TextAlign: Right
    Label   Counter Readiing End:  
    TextBox txtCounterReadiingEnd   TextAlign: Right
    Label   Total HCF:  
    TextBox txtTotalHCF   TextAlign: Right
    Label   Total Gal1ons:  
    TextBox txtTotalGallons   TextAlign: Right
    Label   1st 15 HCF at $3.6121:  
    TextBox txtFirst15HCF   TextAlign: Right
    Label   Next 10 HCF at $3.9180:  
    TextBox txtNext10HCF   TextAlign: Right
    Label   Remaining HCF at $4.2763:  
    TextBox txtRemainingHCF   TextAlign: Right
    Label   Sewer Charges:  
    TextBox txtSewerCharges   TextAlign: Right
    Label   Storm Charges:  
    TextBox txtStormCharges   TextAlign: Right
    Label   Water Usage Charges  
    TextBox txtWaterUsageCharges   TextAlign: Right
    Label Total Charges:    
    TextBox txtTotalCharges   RightAlign: Right
    Label   Water Bill Values Font: Georgia, 9.75pt, style=Bold, Italic
    Label   Local/County Taxes:  
    TextBox txtLocalTaxes  
    Label   State Taxes:  
    TextBox txtStateTaxes    
    Label   _________________________  
    Label   Payment Due Date:  
    TextBox txtPaymentDueDate   TextAlign: Right
    Label   Amount Due:  
    TextBox txtAmountDue   TextAlign: Right
    Label   Late Payment Due Date:  
    TextBox txtLatePaymentDueDate   TextAlign: Right
    Label   Late Payment Amount Due:  
    TextBox txtLatePaymentAmountDue   TextAlign: Right
    Label   _________________________  
    Label   Water Bill #:  
    TextBox txtBillNumber   TextAlign: Right
    Button btnSaveWaterBill Save Water Bill  
    Button btnReviewWaterBill Review Water Bill...  
    Button btnClose Close  
  52. Double-click an unoccupied area of the form to access its Load event
  53. Return to the form and click the Account # text box
  54. In the Properties window, click the Events button Events
  55. In the Events section of the Properties window, double-click Leave
  56. Return to the form and double-click the Service Start Date date time picker
  57. Return to the form and double-click the Service End Date date time picker
  58. Return to the form and click the Counter Reading End text box
  59. In the Events section of the Properties window, double-click Leave
  60. Return to the form and double-click the Save Water Bill button
  61. Return to the form and double-click the Review Water Bill button
  62. Return to the form and double-click the Close button
  63. Change the document as follows:
    using System;
    using System.IO;
    using System.Xml;
    using System.Windows.Forms;
    
    namespace WaterDistributionCompany1
    {
        public partial class BillPreparation : Form
        {
            public BillPreparation()
            {
                InitializeComponent();
            }
    
            private void BillPreparation_Load(object sender, EventArgs e)
            {
                Random rndNumber = new Random();
    
                txtBillNumber.Text = rndNumber.Next(100001, 999999).ToString();
            }
    
            void IdentifyCustomer()
            {
                if (string.IsNullOrEmpty(txtAccountNumber.Text))
                    return;
    
                XmlDocument xdCustomers = new XmlDocument();
                FileInfo fiCustomers = new FileInfo("../../Customers.xml");
    
                // The user must provide a valid account meter.
                // To start, find out if a file for customers accounts exists already.
                if( fiCustomers.Exists == true )
                {
                    // If a file for water meters exists, open it
                    using (FileStream fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open,
                                                                     FileAccess.Read, FileShare.Read))
                    {
                        // Store the list of customers in an XML DOM
                        xdCustomers.Load(fsCustomers);
    
                        // Create a list of child nodes of the root node
                        XmlNodeList xnlCustomers = xdCustomers.DocumentElement.ChildNodes;
    
                        // Visit each node of the list of elements
                        foreach (XmlNode xnCustomer in xnlCustomers)
                        {
                            // When you get to a list of nodes, create a list of its children and visit each
                            foreach (XmlNode xnAccountNumber in xnCustomer.ChildNodes)
                            {
                                // If you find a customer whose account number is the same as the account number the user typed, ...
                                if (xnAccountNumber.InnerText == txtAccountNumber.Text)
                                {
                                    // ... display its details
                                    txtMeterNumber.Text = xnAccountNumber.NextSibling.InnerText;
                                    txtCustomerName.Text = xnAccountNumber.NextSibling.NextSibling.InnerText + " " + xnAccountNumber.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtAddress.Text      = xnAccountNumber.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtCity.Text         = xnAccountNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtCounty.Text       = xnAccountNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtState.Text        = xnAccountNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtZIPCode.Text      = xnAccountNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                }
                            }
                        }
                    }
                }
            }
    
            void IdentifyWaterMeter()
            {
                IdentifyCustomer();
    
                if( string.IsNullOrEmpty(txtMeterNumber.Text) )
                    return;
    
                XmlDocument xdWaterMeters = new XmlDocument();
                string strFileWaterMeters = "../../WaterMeters.xml";
    
                if (File.Exists(strFileWaterMeters))
                {
                    using (FileStream fsWaterMeters = new FileStream(strFileWaterMeters, FileMode.Open,
                                                                     FileAccess.Read, FileShare.Read))
                    {
                        xdWaterMeters.Load(fsWaterMeters);
    
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement.ChildNodes;
    
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            foreach (XmlNode xnMeterNumber in xnWaterMeter.ChildNodes)
                            {
                                if (xnMeterNumber.InnerText == txtMeterNumber.Text)
                                {
                                    txtMeterDetails.Text = xnMeterNumber.NextSibling.InnerText + " " + xnMeterNumber.NextSibling.NextSibling.InnerText + " (Meter #: " + txtMeterNumber.Text + ")";
                                    break;
                                }
                            }
                        }
                    }
                }
            }
    
            private void txtAccountNumber_Leave(object sender, EventArgs e)
            {
                IdentifyWaterMeter();
            }
    
            private void dtpServiceStartDate_ValueChanged(object sender, EventArgs e)
            {
                DateTime dtStart = dtpServiceStartDate.Value;
                DateTime dtEnd = dtpServiceEndDate.Value;
                TimeSpan tsDays = dtEnd.Subtract(dtStart);
    
                txtNumberOfDays.Text = tsDays.Days.ToString();
    
                txtPaymentDueDate.Text = dtpServiceEndDate.Value.AddDays(28).ToShortDateString();
                txtLatePaymentDueDate.Text = dtpServiceEndDate.Value.AddDays(45).ToShortDateString();
            }
    
            private void dtpServiceEndDate_ValueChanged(object sender, EventArgs e)
            {
                dtpServiceStartDate_ValueChanged(sender, e);
            }
    
            private void txtCounterReadingEnd_Leave(object sender, EventArgs e)
            {
                /* Let's compute the numbers for the water bill.
                 * The following calculations are not based on anything real.
                 * I used my own rough estimates with weird non-extensive research based on nothing.
                 * These calculations are for demonstration purposes only for our lesson. */
                double next10HCF;
                double first15HCF;
                double remainingHCF;
    
                double counterReadingStart = double.Parse(txtCounterReadingStart.Text);
                double counterReadingEnd = double.Parse(txtCounterReadingEnd.Text);
    
                double totalHCF = counterReadingEnd - counterReadingStart;
                int totalGallons = (int)(totalHCF * 748.05);
    
                if (totalHCF <= 15)
                {
                    first15HCF = totalHCF * 3.612;
                    next10HCF = 0;
                    remainingHCF = 0;
                }
                else if (totalHCF <= 25)
                {
                    first15HCF = 15 * 3.612;
                    next10HCF = (totalHCF - 15) * 3.918;
                    remainingHCF = 0;
                }
                else
                {
                    first15HCF = 15 * 3.612;
                    next10HCF = 10 * 3.918;
                    remainingHCF = (totalHCF - 25) * 2.2763;
                }
    
                double waterUsageCharge = first15HCF + next10HCF + remainingHCF;
                double sewerCharge = waterUsageCharge * 0.252;
                double stormCharge = waterUsageCharge * 0.0025;
                double totalCharges = waterUsageCharge + sewerCharge + stormCharge;
                double countyTaxes = totalCharges * 0.005;
                double stateTaxes = totalCharges * 0.0152;
                double amountDue = totalCharges + countyTaxes + stateTaxes;
    
                txtTotalHCF.Text = totalHCF.ToString("F");
                txtNext10HCF.Text = next10HCF.ToString("F");
                txtAmountDue.Text = amountDue.ToString("F");
                txtStateTaxes.Text = stateTaxes.ToString("F");
                txtFirst15HCF.Text = first15HCF.ToString("F");
                txtSewerCharges.Text = sewerCharge.ToString("F");
                txtStormCharges.Text = stormCharge.ToString("F");
                txtLocalTaxes.Text = countyTaxes.ToString("F");
                txtTotalGallons.Text = totalGallons.ToString("F");
                txtRemainingHCF.Text = remainingHCF.ToString("F");
                txtTotalCharges.Text = totalCharges.ToString("F");
                txtLatePaymentAmountDue.Text = (amountDue + 8.95).ToString("F");
                txtWaterUsageCharges.Text = waterUsageCharge.ToString("F");
            }
    
            private void btnSaveWaterBill_Click(object sender, EventArgs e)
            {
                XmlDocument xdWaterBills = new XmlDocument();
                string strFileWaterBills = "../../WaterBills.xml";
    
                if( string.IsNullOrEmpty(txtBillNumber.Text) )
                {
                    MessageBox.Show("You must enter an invoice/bill number.", "Water Distribution Company");
                    return;
                }
    
                if (string.IsNullOrEmpty(txtAccountNumber.Text))
                {
                    MessageBox.Show("You must specify the customer's account number.", "Water Distribution Company");
                    return;
                }
    
                if (string.IsNullOrEmpty(txtMeterNumber.Text))
                {
                    MessageBox.Show("You must enter a meter number.", "Water Distribution Company");
                    return;
                }
    
                if (File.Exists(strFileWaterBills))
                {
                    using (FileStream fsWaterBills = new FileStream(strFileWaterBills, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
                    {
                        // ... and put the records in the DOM
                        xdWaterBills.Load(fsWaterBills);
                    }
                }
                else
                {
                    xdWaterBills.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                                         "<water-bills></water-bills>");
                }
                
                XmlElement xeWaterBill = xdWaterBills.CreateElement("water-bill");
                
                xeWaterBill.InnerXml = "<bill-number>" + txtBillNumber.Text + "</bill-number>" +
                                       "<account-number>" + txtAccountNumber.Text + "</account-number>" +
                                       "<meter-reading-start-date>" + dtpServiceStartDate.Value.ToShortDateString() + "</meter-reading-start-date>" +
                                       "<meter-reading-end-date>" + dtpServiceEndDate.Value.ToShortDateString() + "</meter-reading-end-date>" +
                                       "<number-of-days>" + txtNumberOfDays.Text + "</number-of-days>" +
                                       "<counter-reading-start>" + txtCounterReadingStart.Text + "</counter-reading-start>" +
                                       "<counter-reading-end>" + txtCounterReadingEnd.Text + "</counter-reading-end>" +
                                       "<total-hcf>" + txtTotalHCF.Text + "</total-hcf>" +
                                       "<total-gallons>" + txtTotalGallons.Text + "</total-gallons>" +
                                       "<first-15-hcf>" + txtFirst15HCF.Text + "</first-15-hcf>" +
                                       "<next-10-hcf>" + txtNext10HCF.Text + "</next-10-hcf>" +
                                       "<remaining-hcf>" + txtRemainingHCF.Text + "</remaining-hcf>" +
                                       "<sewer-charges>" + txtSewerCharges.Text + "</sewer-charges>" +
                                       "<storm-charges>" + txtStormCharges.Text + "</storm-charges>" +
                                       "<water-usage-charges>" + txtWaterUsageCharges.Text + "</water-usage-charges>" +
                                       "<total-charges>" + txtTotalCharges.Text + "</total-charges>" +
                                       "<local-taxes>" + txtLocalTaxes.Text + "</local-taxes>" +
                                       "<state-taxes>" + txtStateTaxes.Text + "</state-taxes>" +
                                       "<payment-due-date>" + txtPaymentDueDate.Text + "</payment-due-date>" +
                                       "<amount-due>" + txtAmountDue.Text + "</amount-due>" +
                                       "<late-payment-due-date>" + txtLatePaymentDueDate.Text + "</late-payment-due-date>" +
                                       "<late-amount-due>" + txtLatePaymentAmountDue.Text + "</late-amount-due>";
                
                xdWaterBills.DocumentElement.PrependChild(xeWaterBill);
                
                using (FileStream fsWaterBills = new FileStream(strFileWaterBills, FileMode.Create, FileAccess.Write, FileShare.Write))
                {
                    xdWaterBills.Save(fsWaterBills);
                }
    
                Close();
            }
    
            private void btnReviewWaterBill_Click(object sender, EventArgs e)
            {
                BillEditor be = new BillEditor();
    
                be.ShowDialog();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  64. Click the BillEditor.cs [Design] tab to access its form
  65. Design the form as follows:

    Using the Siblings of an XML Node

    Control (Name) Text Other Properties
    Label   Customer Account Information Font: Georgia, 9.75pt, style=Bold, Italic
    Label   Account #:  
    TextBox txtAccountNumber    
    Label   Customer Name:  
    TextBox txtCustomerName    
    TextBox txtAddress    
    TextBox txtCity    
    TextBox: txtCounty    
    TextBox txtState    
    TextBox txtZIPCode    
    Label   Meter Information Georgia, 9.75pt, style=Bold, Italic
    Label   Meter Details:  
    TextBox txtMeterNumber    
    TextBox txtMeterDetails    
    Label   Meter Reading  
    Label   ___________________  
    Label   Service Start Date:  
    DateTimeIcker dtpServiceStartDate   Format: Short
    Label   Service End Date:  
    DateTimeIcker dtpServiceEndDate   Format: Short
    Label   Number of Days:  
    TextBox txtNumberOfDays   TextAlign: Right
    Label   Counter Readiing Start:  
    TextBox txtCounterReadiingStart   TextAlign: Right
    Label   Counter Readiing End:  
    TextBox txtCounterReadiingEnd   TextAlign: Right
    Label   Total HCF:  
    TextBox txtTotalHCF   TextAlign: Right
    Label   Total Gal1ons:  
    TextBox txtTotalGallons   TextAlign: Right
    Label   1st 15 HCF at $3.6121:  
    TextBox txtFirst15HCF   TextAlign: Right
    Label   Next 10 HCF at $3.9180:  
    TextBox txtNext10HCF   TextAlign: Right
    Label   Remaining HCF at $4.2763:  
    TextBox txtRemainingHCF   TextAlign: Right
    Label   Sewer Charges:  
    TextBox txtSewerCharges   TextAlign: Right
    Label   Storm Charges:  
    TextBox txtStormCharges   TextAlign: Right
    Label   Water Usage Charges  
    TextBox txtWaterUsageCharges   TextAlign: Right
    Label Total Charges:    
    TextBox txtTotalCharges   RightAlign: Right
    Label   Water Bill Values Font: Georgia, 9.75pt, style=Bold, Italic
    Label   Local/County Taxes:  
    TextBox txtLocalTaxes   TextAlign: Right
    Label   State Taxes:  
    TextBox txtStateTaxes    
    Label   _________________________  
    Label   Payment Due Date:  
    TextBox txtPaymentDueDate   TextAlign: Right
    Label   Amount Due:  
    TextBox txtAmountDue   TextAlign: Right
    Label   Late Payment Due Date:  
    TextBox txtLatePaymentDueDate   TextAlign: Right
    Label   Late Payment Amount Due:  
    TextBox txtLatePaymentAmountDue   TextAlign: Right
    Label   _________________________  
    Label   Water Bill #:  
    TextBox txtBillNumber   TextAlign: Right
    Button btnOpen Open  
    Button btnSaveWaterBill Save Water Bill  
    Button btnReviewWaterBill Review Water Bill...  
    Button btnClose Close  
  66. On the form, double-click the Open button
  67. Return to the form and click the Account # text box
  68. In the Properties window, click the Events button Events
  69. In the Events section of the Properties window, double-click Leave
  70. Return to the form and double-click the Service Start Date date time picker
  71. Return to the form and double-click the Service End Date date time picker
  72. Return to the form and click the Counter Reading End text box
  73. In the Events section of the Properties window, double-click Leave
  74. Return to the form and double-click the Save Water Bill button
  75. Return to the form and double-click the Review Water Bill button
  76. Return to the form and double-click the Close button
  77. Change the document as follows:
    using System;
    using System.IO;
    using System.Xml;
    using System.Windows.Forms;
    
    namespace WaterDistributionCompany1
    {
        public partial class BillEditor : Form
        {
            public BillEditor()
            {
                InitializeComponent();
            }
    
            void IdentifyCustomer()
            {
                if (string.IsNullOrEmpty(txtAccountNumber.Text))
                    return;
    
                XmlDocument xdCustomers = new XmlDocument();
                FileInfo fiCustomers = new FileInfo("../../Customers.xml");
    
                if (fiCustomers.Exists == true)
                {
                    // If a file for water meters exists, open it
                    using (FileStream fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open,
                                                                     FileAccess.Read, FileShare.Read))
                    {
                        // Store the list of customers in an XML DOM
                        xdCustomers.Load(fsCustomers);
    
                        // Create a list of child nodes of the root node
                        XmlNodeList xnlCustomers = xdCustomers.DocumentElement.ChildNodes;
    
                        // Visit each node of the list of elements
                        foreach (XmlNode xnCustomer in xnlCustomers)
                        {
                            // When you get to a list of nodes, create a list of its children and visit each
                            foreach (XmlNode xnAccountNumber in xnCustomer.ChildNodes)
                            {
                                // If you find a customer whose account number is the same as the account number the user typed, ...
                                if (xnAccountNumber.InnerText == txtAccountNumber.Text)
                                {
                                    // ... display its details
                                    txtMeterNumber.Text  = xnAccountNumber.NextSibling.InnerText;
                                    txtCustomerName.Text = xnAccountNumber.NextSibling.NextSibling.InnerText + " " +
                                                           xnAccountNumber.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtAddress.Text      = xnAccountNumber.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtCity.Text         = xnAccountNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtCounty.Text       = xnAccountNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtState.Text        = xnAccountNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtZIPCode.Text      = xnAccountNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                }
                            }
                        }
                    }
                }
            }
    
            void IdentifyWaterMeter()
            {
                if (string.IsNullOrEmpty(txtAccountNumber.Text))
                    return;
    
                IdentifyCustomer();
    
                if (string.IsNullOrEmpty(txtMeterNumber.Text))
                    return;
    
                XmlDocument xdWaterMeters = new XmlDocument();
                string strFileWaterMeters = "../../WaterMeters.xml";
    
                if (File.Exists(strFileWaterMeters))
                {
                    using (FileStream fsWaterMeters = new FileStream(strFileWaterMeters, FileMode.Open,
                                                                     FileAccess.Read, FileShare.Read))
                    {
                        xdWaterMeters.Load(fsWaterMeters);
    
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement.ChildNodes;
    
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            foreach (XmlNode xnMeterNumber in xnWaterMeter.ChildNodes)
                            {
                                if (xnMeterNumber.InnerText == txtMeterNumber.Text)
                                {
                                    txtMeterDetails.Text = xnMeterNumber.NextSibling.InnerText + " " + 
                                                           xnMeterNumber.NextSibling.NextSibling.InnerText +
                                                           " (Meter #: " + txtMeterNumber.Text + ")";
                                    break;
                                }
                            }
                        }
                    }
                }
            }
    
            private void btnOpen_Click(object sender, EventArgs e)
            {
                XmlDocument xdWaterBills = new XmlDocument();
                FileInfo fiWaterBills = new FileInfo("../../WaterBills.xml");
    
                if (fiWaterBills.Exists == true)
                {
                    using (FileStream fsWaterBills = new FileStream(fiWaterBills.FullName, FileMode.Open,
                                                                    FileAccess.Read, FileShare.Read))
                    {
                        xdWaterBills.Load(fsWaterBills);
    
                        XmlNodeList xnlWaterBills = xdWaterBills.DocumentElement.ChildNodes;
    
                        foreach (XmlNode xnWaterBill in xnlWaterBills)
                        {
                            foreach (XmlNode xnBillNumber in xnWaterBill.ChildNodes)
                            {
                                if (xnBillNumber.InnerText == txtBillNumber.Text)
                                {
                                    txtAccountNumber.Text        =                xnBillNumber.NextSibling.InnerText;
                                    dtpServiceStartDate.Value    = DateTime.Parse(xnBillNumber.NextSibling.NextSibling.InnerText);
                                    dtpServiceEndDate.Value      = DateTime.Parse(xnBillNumber.NextSibling.NextSibling.NextSibling.InnerText);
                                    txtNumberOfDays.Text         =                xnBillNumber.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtCounterReadingStart.Text  =                xnBillNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtCounterReadingEnd.Text    =                xnBillNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtTotalHCF.Text             =                xnBillNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtTotalGallons.Text         =                xnBillNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtFirst15HCF.Text           =                xnBillNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtNext10HCF.Text            =                xnBillNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtRemainingHCF.Text         =                xnBillNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtSewerCharges.Text         =                xnBillNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtStormCharges.Text         =                xnBillNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtWaterUsageCharges.Text    =                xnBillNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtTotalCharges.Text         =                xnBillNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtLocalTaxes.Text           =                xnBillNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtStateTaxes.Text           =                xnBillNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtPaymentDueDate.Text       =                xnBillNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtAmountDue.Text            =                xnBillNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtLatePaymentDueDate.Text   =                xnBillNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                    txtLatePaymentAmountDue.Text =                xnBillNumber.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                }
                            }
                        }
                    }
                }
    
                IdentifyWaterMeter();
            }
    
            private void txtAccountNumber_Leave(object sender, EventArgs e)
            {
                IdentifyWaterMeter();
            }
    
            private void dtpServiceStartDate_ValueChanged(object sender, EventArgs e)
            {
                DateTime dtStart = dtpServiceStartDate.Value;
                DateTime dtEnd = dtpServiceEndDate.Value;
                TimeSpan tsDays = dtEnd.Subtract(dtStart);
    
                txtNumberOfDays.Text = tsDays.Days.ToString();
    
                txtPaymentDueDate.Text = dtpServiceEndDate.Value.AddDays(28).ToShortDateString();
                txtLatePaymentDueDate.Text = dtpServiceEndDate.Value.AddDays(45).ToShortDateString();
            }
    
            private void dtpServiceEndDate_ValueChanged(object sender, EventArgs e)
            {
                dtpServiceStartDate_ValueChanged(sender, e);
            }
    
            private void txtCounterReadingEnd_Leave(object sender, EventArgs e)
            {
                double next10HCF;
                double first15HCF;
                double remainingHCF;
    
                double counterReadingStart = double.Parse(txtCounterReadingStart.Text);
                double counterReadingEnd = double.Parse(txtCounterReadingEnd.Text);
    
                double totalHCF = counterReadingEnd - counterReadingStart;
                int totalGallons = (int)(totalHCF * 748.05);
    
                if (totalHCF <= 15)
                {
                    first15HCF = totalHCF * 3.612;
                    next10HCF = 0;
                    remainingHCF = 0;
                }
                else if (totalHCF <= 25)
                {
                    first15HCF = 15 * 3.612;
                    next10HCF = (totalHCF - 15) * 3.918;
                    remainingHCF = 0;
                }
                else
                {
                    first15HCF = 15 * 3.612;
                    next10HCF = 10 * 3.918;
                    remainingHCF = (totalHCF - 25) * 2.2763;
                }
    
                double waterUsageCharge = first15HCF + next10HCF + remainingHCF;
                double sewerCharge = waterUsageCharge * 0.252;
                double stormCharge = waterUsageCharge * 0.0025;
                double totalCharges = waterUsageCharge + sewerCharge + stormCharge;
                double countyTaxes = totalCharges * 0.005;
                double stateTaxes = totalCharges * 0.0152;
                double amountDue = totalCharges + countyTaxes + stateTaxes;
    
                txtTotalHCF.Text = totalHCF.ToString("F");
                txtNext10HCF.Text = next10HCF.ToString("F");
                txtAmountDue.Text = amountDue.ToString("F");
                txtStateTaxes.Text = stateTaxes.ToString("F");
                txtFirst15HCF.Text = first15HCF.ToString("F");
                txtSewerCharges.Text = sewerCharge.ToString("F");
                txtStormCharges.Text = stormCharge.ToString("F");
                txtLocalTaxes.Text = countyTaxes.ToString("F");
                txtTotalGallons.Text = totalGallons.ToString("F");
                txtRemainingHCF.Text = remainingHCF.ToString("F");
                txtTotalCharges.Text = totalCharges.ToString("F");
                txtLatePaymentAmountDue.Text = (amountDue + 8.95).ToString("F");
                txtWaterUsageCharges.Text = waterUsageCharge.ToString("F");
            }
    
            private void btnUpdateWaterBill_Click(object sender, EventArgs e)
            {
                if (string.IsNullOrEmpty(txtBillNumber.Text))
                {
                    MessageBox.Show("You must enter the bill number of the water " +
                                    "bill you want to update (and click the Open button).",
                                    "Water Distribution Company");
                    return;
                }
    
                if (string.IsNullOrEmpty(txtAccountNumber.Text))
                    return;
    
                if (string.IsNullOrEmpty(txtMeterNumber.Text))
                    return;
    
                XmlNode xnOriginalWaterBill = null;
    
                XmlDocument xdWaterBills = new XmlDocument();
                FileInfo fiWaterBills = new FileInfo("../../WaterBills.xml");
    
                if (fiWaterBills.Exists == true)
                {
                    using (FileStream fsWaterBills = new FileStream(fiWaterBills.FullName, FileMode.Open,
                                                                    FileAccess.Read, FileShare.Read))
                    {
                        xdWaterBills.Load(fsWaterBills);
    
                        XmlNodeList xnlWaterBills = xdWaterBills.DocumentElement.ChildNodes;
    
                        foreach (XmlNode xnWaterBill in xnlWaterBills)
                        {
                            foreach (XmlNode xnBillNumber in xnWaterBill.ChildNodes)
                            {
                                if (xnBillNumber.InnerText == txtBillNumber.Text)
                                {
                                    xnOriginalWaterBill = xnWaterBill;
                                    break;
                                }
                            }
                        }
                    }
                }
    
                XmlElement xeUpdatedWaterBill = xdWaterBills.CreateElement("water-bill");
    
                string strUpdatedWaterBill = "<bill-number>" + txtBillNumber.Text + "</bill-number>" +
                                             "<account-number>" + txtAccountNumber.Text + "</account-number>" +
                                             "<meter-reading-start-date>" + dtpServiceStartDate.Value.ToShortDateString() + "</meter-reading-start-date>" +
                                             "<meter-reading-end-date>" + dtpServiceEndDate.Value.ToShortDateString() + "</meter-reading-end-date>" +
                                             "<number-of-days>" + txtNumberOfDays.Text + "</number-of-days>" +
                                             "<counter-reading-start>" + txtCounterReadingStart.Text + "</counter-reading-start>" +
                                             "<counter-reading-end>" + txtCounterReadingEnd.Text + "</counter-reading-end>" +
                                             "<total-hcf>" + txtTotalHCF.Text + "</total-hcf>" +
                                             "<total-gallons>" + txtTotalGallons.Text + "</total-gallons>" +
                                             "<first-15-hcf>" + txtFirst15HCF.Text + "</first-15-hcf>" +
                                             "<next-10-hcf>" + txtNext10HCF.Text + "</next-10-hcf>" +
                                             "<remaining-hcf>" + txtRemainingHCF.Text + "</remaining-hcf>" +
                                             "<sewer-charges>" + txtSewerCharges.Text + "</sewer-charges>" +
                                             "<storm-charges>" + txtStormCharges.Text + "</storm-charges>" +
                                             "<water-usage-charges>" + txtWaterUsageCharges.Text + "</water-usage-charges>" +
                                             "<total-charges>" + txtTotalCharges.Text + "</total-charges>" +
                                             "<local-taxes>" + txtLocalTaxes.Text + "</local-taxes>" +
                                             "<state-taxes>" + txtStateTaxes.Text + "</state-taxes>" +
                                             "<payment-due-date>" + txtPaymentDueDate.Text + "</payment-due-date>" +
                                             "<amount-due>" + txtAmountDue.Text + "</amount-due>" +
                                             "<late-payment-due-date>" + txtLatePaymentDueDate.Text + "</late-payment-due-date>" +
                                             "<late-amount-due>" + txtLatePaymentAmountDue.Text + "</late-amount-due>";
    
                xeUpdatedWaterBill.InnerXml = strUpdatedWaterBill;
    
                xdWaterBills.DocumentElement.ReplaceChild(xeUpdatedWaterBill, xnOriginalWaterBill);
    
                using (FileStream fsCustomers = new FileStream(fiWaterBills.FullName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
                {
                    xdWaterBills.Save(fsCustomers);
                }
    
                Close();
            }
    
            private void btnNewWaterBill_Click(object sender, EventArgs e)
            {
                BillPreparation bp = new BillPreparation();
                bp.ShowDialog();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  78. In the Solution Explorer, right-click Form1.cs and click Rename
  79. Type WaterDistributionCompany (to get WaterDistributionCompany.cs) and press Enter three times to display the form
  80. Design the form as follows:

    Water Distribution Company

    Control (Name) Text
    Button btnCustomers Customers...
    Button btnWaterMeters Water Meters...
    Button btnNewGasBill New Water Bill...
    Button btnWaterBillReview Water Bill Review...
    Button btnClose Close
  81. On the form, double-click the Customers... button
  82. Return to the form and double-click the Water Meters... button
  83. Return to the form and double-click the New Water Bill... button
  84. Return to the form and double-click the Water Bill Review... button
  85. Return to the form and double-click the Close button
  86. Change the document as follows:
    using System;
    using System.Windows.Forms;
    
    namespace WaterDistributionCompany1
    {
        public partial class WaterDistributionCompany : Form
        {
            public WaterDistributionCompany()
            {
                InitializeComponent();
            }
    
            private void btnCustomers_Click_1(object sender, EventArgs e)
            {
                Customers clients = new Customers();
    
                clients.ShowDialog();
            }
    
            private void btnWaterMeters_Click(object sender, EventArgs e)
            {
                WaterMeters wm = new WaterMeters();
    
                wm.ShowDialog();
            }
    
            private void btnNewWaterBill_Click(object sender, EventArgs e)
            {
                BillPreparation bp = new BillPreparation();
    
                bp.ShowDialog();
            }
    
            private void btnWaterBillReview_Click(object sender, EventArgs e)
            {
                BillEditor be = new BillEditor();
                be.ShowDialog();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  87. To execute the project, on the main menu, click Debug -> Start Without Debugging:

    Getting an Item from a Collection

  88. Click the Water Meters button:

    Maintenance of XML Elements

  89. Close the Water Meters form
  90. Click the Customers button:

    Locating an Element Using its Name

  91. Click the New Customer button:

    Water for a Shining Life

  92. Type the values in the text boxes as in the following table. After each record, click the Save button:

    Account # Meter # First Name Last Name Address City County State ZIP Code
    2958-314-5294 392-44-572 Nicholas Thorn 2599 Phenicia Road Silver Spring Montgomery MD 20906
    8046-728-5060 304-861 Augustino Derbez 7507 Westchester Ave Washington   DC 20008
    4024-850-0482 820-418 Marianne Pattersen 10572 Maya Blvd Frederick Frederick MD 20111
    1848-205-3313 925-935 Frank Nounkeu 13931 Wellington Street College Park Pringe George MD 20740
    7029-371-8594 293-740 Danielle Dormand 2515 Guthierez Street Falls Church   VA 22046

    Locating an Element Using its Name

  93. Close the Customers form
  94. Click the green arrow to position the new bottle somwhere around the back side of the table:

    Modeling a Picnic Table

  95. Type the following values in the text boxes and select others from date time pickers:

    Water Bill # 294758
    Account # 7518-302-6895
    Service Start Date 10/5/2020
    Service End Date 1/12/2021
    Meter Reading Start 163
    Reading End 196

    Introducing Node Creation

  96. Click the Save Water Bill button
  97. Click the New Water Bill button again
  98. Set some values as follows:
    Water Bill # Account # Service Start Date: Service End Date Counter Reading Start Counter Reading End
    682048 4820-375-2842 10/22/2020 1/18/2021 109992 109998
    137579 2038-413-9680 10/22/2020 1/22/2021 137926 137975
    480465 9279-570-8394 11/14/2020 2/7/2021 6268 6275
    829736 7518-302-6895 1/12/2021 4/8/2021 114 118
  99. Close the forms and return to your programming environment
  100. Close the form and return to your programming environment

Practical LearningPractical Learning: Ending the Lesson

  1. Start Microsoft Visual Studio and create a Windows Forms application named GasUtilityCompany1
  2. On the main menu, click Project -> Add New Item...
  3. In the left list of the Add New Item dialog box, click Data. In the middle list, click XML File
  4. Change the file name to GasMeters
  5. Click Add
  6. Change the content of the document as follows:
    <?xml version="1.0" encoding="utf-8" ?>
    <?xml version="1.0" encoding="utf-8" ?>
    <gas-meters>
    	<gas-meter>
    		<meter-number>582741-38</meter-number>
    		<make>Sinton International</make>
    		<model>D-244</model>
    		<meter-reading-date>2021-05-10</meter-reading-date>
    		<counter-value>138</counter-value>
    	</gas-meter>
    	<gas-meter>
    		<meter-number>293847-27</meter-number>
    		<make>Archimeda</make>
    		<model>LP2066</model>
    		<meter-reading-date>2021-08-03</meter-reading-date>
    		<counter-value>2866</counter-value>
    	</gas-meter>
    	<gas-meter>
    		<meter-number>928731-59</meter-number>
    		<make>EnvioSmart</make>
    		<model>84-D9703</model>
    		<meter-reading-date>2020-12-08</meter-reading-date>
    		<counter-value>8016</counter-value>
    	</gas-meter>
    	<gas-meter>
    		<meter-number>520246-85</meter-number>
    		<make>Garland Worldwide</make>
    		<model>GFH-2260</model>
    		<meter-reading-date>2021-05-21</meter-reading-date>
    		<counter-value>22683</counter-value>
    	</gas-meter>
    	<gas-meter>
    		<meter-number>797047-27</meter-number>
    		<make>Archimeda</make>
    		<model>LP2066</model>
    		<meter-reading-date>2021-10-04</meter-reading-date>
    		<counter-value>725</counter-value>
    	</gas-meter>
    	<gas-meter>
    		<meter-number>425837-14</meter-number>
    		<make>EnvioSmart</make>
    		<model>28-G4428</model>
    		<meter-reading-date>2021-01-01</meter-reading-date>
    		<counter-value>6114</counter-value>
    	</gas-meter>
    	<gas-meter>
    		<meter-number>162460-82</meter-number>
    		<make>Archimeda</make>
    		<model>Di8000</model>
    		<meter-reading-date>2020-06-03</meter-reading-date>
    		<counter-value>15502</counter-value>
    	</gas-meter>
    	<gas-meter>
    		<meter-number>864085-92</meter-number>
    		<make>Sinton International</make>
    		<model>D-244</model>
    		<meter-reading-date>2021-10-05</meter-reading-date>
    		<counter-value>83</counter-value>
    	</gas-meter>
    </gas-meters>
  7. On the main menu of Microsoft Visual Studio, click Project -> Add Form (Windows Forms)...
  8. Change the file name to GasMeters as the name of the form
  9. Click Add
  10. Design the form as follows:

    Introduction to XML

    Control (Name) Text Other Properties
    ListView lvwWaterMeters  
    FullRowSelect: True
    GridLines:     True
    Anchor:		 Top, Bottom, Left, Right
    Button btnClose Close Anchor: Bottom, Right

    List View Columns

    (Name) Text TextAlign Width
    colNumber #   20
    colMeterNumber Meter Number Center 80
    colMake Make   110
    colModel Model   80
    colMeterReadingDate Reading Date Center 80
    colCounterValue Counter Value Right 80
  11. Double-click an unoccupied area of the form to launch its Load event
  12. Return to the form and double-click the Close button
  13. Change the document as follows:
    using System;
    using System.IO;
    using System.Xml;
    using System.Windows.Forms;
    
    namespace QuatroGasCompany1
    {
        public partial class GasMeters : Form
        {
            public GasMeters()
            {
                InitializeComponent();
            }
    
            private void GasMeters_Load(object sender, EventArgs e)
            {
                // Indicate the name of the file that holds the gas meters records
                string fnGasMeters = "../../GasMeters.xml";
                // Create an XML DOM
                XmlDocument xdGasMeters = new XmlDocument();
    
                // Check that a file for gas meters was already created
                if (File.Exists(fnGasMeters))
                {
                    // If that file exists already, open it and store its records in the XML DOM
                    xdGasMeters.Load(fnGasMeters);
                    // Get the root of the XML DOM
                    XmlElement xeGasMeter = xdGasMeters.DocumentElement;
                    // Get a list of the elements under the root of the DOM
                    XmlNodeList xnlGasMeters = xeGasMeter.ChildNodes;
    
                    // This small natural number will be used to count the number of gas meters
                    int i = 0;
    
                    // Just in case the list view was displaying some records, remove them
                    lvwGasMeters.Items.Clear();
    
                    // Visit each XML document in the document
                    foreach (XmlNode xnGasMeter in xnlGasMeters)
                    {
                        // Create a list view item that will hold each record in the list view.
                        // Get the record counter in the first column 
                        ListViewItem lviGasMeter = new ListViewItem((i + 1).ToString()); // #
    
                        /* Get each part of the gas meter to display in its respective column. 
                         * Put it value in the list held by the list view item. */
                        lviGasMeter.SubItems.Add(xnGasMeter.FirstChild.InnerText); // Meter #
                        lviGasMeter.SubItems.Add(xnGasMeter.FirstChild.NextSibling.InnerText); // Make
                        lviGasMeter.SubItems.Add(xnGasMeter.FirstChild.NextSibling.NextSibling.InnerText); // Model
                        lviGasMeter.SubItems.Add(xnGasMeter.FirstChild.NextSibling.NextSibling.NextSibling.InnerText); // Meter Reading Date
                        lviGasMeter.SubItems.Add(xnGasMeter.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.InnerText); // Counter Value
                        // Add the list view item to the list view
                        lvwGasMeters.Items.Add(lviGasMeter);
    
                        // Increase the counter of records
                        i++;
                    }
                }
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  14. To create a new form, on the main menu, click Project -> Add Form (Windows Forms)...
  15. Change the file Name to CustomerNew
  16. Click Add
  17. Using the Properties window, change the following characteristics of the form:
    FormBorderStyle: FixedDialog
    Text:            Gas Utility Company - New Customer
    StartPosition:   CenterScreen
    MaximizeBox:	   False
    MinimizeBox:	   False
  18. Design the form as follows:

    Introducing XML Nodes

    Control (Name) Text Other Properies
    Label   Account #:  
    TextBox txtAccountNumber   Modifiers: Internal
    Label   Meter #:  
    TextBox txtMeterNumber   Modifiers: Internal
    Label   Meter Details:  
    TextBox txtMeterDetails   Modifiers: Internal
    Label   First Name:  
    TextBox txtFirstName   Modifiers: Internal
    Label   Last Name:  
    TextBox txtLastName   Modifiers: Internal
    Label   Address:  
    TextBox txtAddress   Modifiers: Internal
    Label   City:  
    TextBox txtCity   Modifiers: Internal
    Label   County:  
    TextBox txtCounty   Modifiers: Internal
    Label   State:  
    TextBox txtState   Modifiers: Internal
    Label   ZIP Code:  
    TextBox txtZIPCode    
    Button btnSave Save Customer Account DialogResult: OK
    Button btnClose Close DialogResult: Cancel
  19. Click the form to select it and, using the Properties window, change the following characteristics:
    AcceptButton: btnSave
    CancelButton: btnClose
  20. To create a new form, on the main menu, click Project -> Add Form (Windows Forms)...
  21. Change the file name to CustomerEditor
  22. Click Add
  23. Using the Properties window, change the following characteristics of the form:
    FormBorderStyle: FixedDialog
    Text:            Gas Utility Company - Customer Editor
    StartPosition:   CenterScreen
    MaximizeBox:	   False
    MinimizeBox:	   False
  24. Design the form as follows:

    Using the Siblings of an XML Node

    Control (Name) Text Other Properties
    Label   Account #:  
    TextBox txtAccountNumber   Modifiers: Internal
    Button btnOpen Open  
    Label   Meter #:  
    TextBox txtMeterNumber   Modifiers: Internal
    Label   Meter Details:  
    TextBox txtMeterDetails   Modifiers: Internal
    Label   First Name:  
    TextBox   txtFirstName Modifiers: Internal
    Label   Last Name:  
    TextBox txtLastName   Modifiers: Internal
    Label   Address:  
    TextBox txtAddress   Modifiers: Internal
    Label   City:  
    TextBox txtCity   Modifiers: Internal
    Label   County:  
    TextBox txtCounty   Modifiers: Internal
    Label   State:  
    TextBox txtState   Modifiers: Internal
    Label   ZIP Code:  
    TextBox txtZIPCode   Modifiers: Internal
    Button btnUpdateGasMeter Update Gas Meter DialogResult: OK
    Button btnClose Close DialogResult: Cancel
  25. Click the form to select it and, using the Properties window, change the following characteristics:
    AcceptButton: btnUpdateGasMeter
    CancelButton: btnClose
  26. On the form, click the Meter # text box
  27. In the Properties window, click the Events button Events
  28. Double-click Leave
  29. Return to the form and double-click the Open button
  30. Change the document as follows:
    using System;
    using System.IO;
    using System.Xml;
    using System.Windows.Forms;
    
    namespace QuatroGasCompany1
    {
        public partial class CustomerEditor : Form
        {
            public CustomerEditor()
            {
                InitializeComponent();
            }
    
            public void IdentifyGasMeter()
            {
                if (string.IsNullOrEmpty(txtMeterNumber.Text))
                    return;
    
                XmlDocument xdGasMeters = new XmlDocument();
                FileInfo fiGasMeters = new FileInfo("../../GasMeters.xml");
    
                /* This code will run if the user had first put a valid account number; then this 
                 * code is used to find the water meter associated with the customer's account. */
                if(fiGasMeters.Exists == true )
                {
                    // Open the file that contains the water meter details
                    using (FileStream fsGasMeters = new FileStream(fiGasMeters.FullName, FileMode.Open,
                                                                   FileAccess.Read, FileShare.Read))
                    {
                        // Store the list of water meters in an XML DOM
                        xdGasMeters.Load(fiGasMeters.FullName);
    
                        // Create a list of elements based on a node named meter-number
                        XmlNodeList xnlGasMeters = xdGasMeters.DocumentElement.GetElementsByTagName("meter-number");
    
                        // Visit each node of the list of elements
                        foreach (XmlNode xnGasMeter in xnlGasMeters)
                        {
                            // If you find a meter number that is the same as the meter number from the form, ...
                            if (xnGasMeter.InnerText == txtMeterNumber.Text)
                            {
                                // ... display its details
                                txtMeterDetails.Text = xnGasMeter.NextSibling.InnerText + " " + xnGasMeter.NextSibling.NextSibling.InnerText + " (Meter #: " + txtMeterNumber.Text + ")";
                            }
                        }
                    }
                }
            }
    
            private void txtMeterNumber_Leave(object sender, EventArgs e)
            {
                XmlDocument xdCustomers = new XmlDocument();
                string strCustomers = "../../Customers.xml";
                FileInfo fiCustomers = new FileInfo(strCustomers);
    
                if (fiCustomers.Exists == true)
                {
                    using (FileStream fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open,
                                                                   FileAccess.Read, FileShare.Read))
                    {
                        xdCustomers.Load(fsCustomers);
    
                        XmlNodeList xnlCustomers = xdCustomers.DocumentElement.GetElementsByTagName("account-number");
    
                        foreach (XmlNode xnCustomer in xnlCustomers)
                        {
                            if (xnCustomer.InnerText == txtAccountNumber.Text)
                            {
                                txtMeterNumber.Text = xnCustomer.NextSibling.InnerText;
                                txtFirstName.Text = xnCustomer.NextSibling.NextSibling.InnerText;
                                txtLastName.Text = xnCustomer.NextSibling.NextSibling.NextSibling.InnerText;
                                txtAddress.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtCity.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtCounty.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtState.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtZIPCode.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
    
                                break;
                            }
                        }
                    }
                }
    
                IdentifyGasMeter();
            }
    
            private void btnOpen_Click(object sender, EventArgs e)
            {
                string strCustomers = "../../Customers.xml";
                XmlDocument xdCustomers = new XmlDocument();
                FileInfo fiCustomers = new FileInfo(strCustomers);
    
                if( File.Exists(fiCustomers.FullName) == true )
                {
                    using (FileStream fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open,
                                                                   FileAccess.Read, FileShare.Read))
                    {
                        xdCustomers.Load(fsCustomers);
    
                        XmlNodeList xnlCustomers = xdCustomers.DocumentElement.GetElementsByTagName("account-number");
    
                        foreach (XmlNode xnCustomer in xnlCustomers)
                        {
                            if (xnCustomer.InnerText == txtAccountNumber.Text)
                            {
                                txtMeterNumber.Text = xnCustomer.NextSibling.InnerText;
                                txtFirstName.Text = xnCustomer.NextSibling.NextSibling.InnerText;
                                txtLastName.Text = xnCustomer.NextSibling.NextSibling.NextSibling.InnerText;
                                txtAddress.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtCity.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtCounty.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtState.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtZIPCode.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
    
                                break;
                            }
                        }
                    }
                }
    
                IdentifyGasMeter();
            }
        }
    }
  31. To create another form, on the main menu, click Project -> Add New Form (Windows Forms)...
  32. Change the file name to Customers
  33. Click Add
  34. Using the Properties window, change the following characteristics of the form:
    Text:          Gas Utility Company - Customers
    StartPosition: CenterScreen
    MaximizeBox:	 False
  35. Design the form as follows:

    Using the Siblings of an XML Node

    Control (Name) Text Other Properties
    ListView lvwCustomers  
    FullRowSelect: True
    GridLines:     True
    Anchor:        Top, Bottom, Left, Right
    Button btnNewCustomer New Customer Anchor: Bottom, Right
    Button btnCustomerEditor Customer Editor... Anchor: Bottom, Right
    Button btnClose Close Anchor: Bottom, Right

    List View Columns

    (Name) Text TextAlign Width
    colNumber #   20
    colAccountNumber Account #   90
    colMeterNumber Meter Number Center 80
    colFirstName First Name   65
    colLastName Last Name   65
    colAddress Address   135
    colCity City   80
    colCounty County   80
    colState State Center 40
    colZIPCode ZIP Code    
  36. Double-click an unoccupied area of the form to generate its Load event
  37. Return to the form and double-click the New Customer button
  38. Return to the form and double-click the Customer Editor button
  39. Return to the form and double-click the Close button
  40. Change the document as follows:
    using System;
    using System.IO;
    using System.Xml;
    using System.Windows.Forms;
    
    namespace QuatroGasCompany1
    {
        public partial class Customers : Form
        {
            public Customers()
            {
                InitializeComponent();
            }
    
            void ShowCustomers()
            {
                XmlDocument xdCustomers = new XmlDocument();
                FileInfo fiCustomers = new FileInfo("../../Customers.xml");
    
                if (fiCustomers.Exists)
                {
                    xdCustomers.Load(fiCustomers.FullName);
                    XmlElement xeCustomer = xdCustomers.DocumentElement;
                    XmlNodeList xnlCustomers = xeCustomer.ChildNodes;
    
                    int i = 1;
    
                    lvwCustomers.Items.Clear();
    
                    foreach (XmlNode xnCustomer in xnlCustomers)
                    {
                        ListViewItem lviCustomer = new ListViewItem(i.ToString()); // #
    
                        lviCustomer.SubItems.Add(xnCustomer.FirstChild.InnerText); // Account #
                        lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling.InnerText); // Meter #
                        lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling.NextSibling.InnerText); // First Name
                        lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling.NextSibling.NextSibling.InnerText); // Last Name
                        lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.InnerText); // Address
                        lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText); // City
                        lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText); // County
                        lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText); // State
                        lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText); // ZIP Code
    
                        lvwCustomers.Items.Add(lviCustomer);
    
                        i++;
                    }
                }
            }
    
            private void Customers_Load(object sender, EventArgs e)
            {
                ShowCustomers();
            }
    
            private void btnNewCustomer_Click(object sender, EventArgs e)
            {
                CustomerNew cn = new CustomerNew();
    
                if (cn.ShowDialog() == DialogResult.OK)
                {
                    if (string.IsNullOrEmpty(cn.txtAccountNumber.Text))
                    {
                        MessageBox.Show("You must enter a (unique) account number for the customer." +
                                        Environment.NewLine +
                                        "We cannot create a customer account that doesn't have an account number.",
                                        "Gas Utility Company");
    
                        // If the user doesn't provide an account number, don't do nothing.
                        return;
                    }
    
                    if (string.IsNullOrEmpty(cn.txtMeterNumber.Text))
                    {
                        MessageBox.Show("You must type a (unique) number for the gas meter.", "Gas Utility Company");
    
                        // If the user doesn't provide a meter number, don't do nothing.
                        return;
                    }
    
                    XmlDocument xdCustumers = new XmlDocument();
                    FileInfo fiCustomers = new FileInfo("../../Customers.xml");
    
                    if (fiCustomers.Exists == true)
                    {
                        using (FileStream fsCustumers = new FileStream(fiCustomers.FullName, FileMode.Open,
                                                                       FileAccess.Read, FileShare.Read))
                        {
                            xdCustumers.Load(fsCustumers);
                        }
                    }
                    else
                    {
                        xdCustumers.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                                            "<custumers></custumers>");
                    }
    
                    XmlElement xeCustumer = xdCustumers.CreateElement("custumer");
                    string strCustumer    = "<account-number>" + cn.txtAccountNumber.Text + "</account-number>" +
                                            "<meter-number>" + cn.txtMeterNumber.Text + "</meter-number>" +
                                            "<first-name>" + cn.txtFirstName.Text + "</first-name>" +
                                            "<last-name>" + cn.txtLastName.Text + "</last-name>" +
                                            "<address>" + cn.txtAddress.Text + "</address>" +
                                            "<city>" + cn.txtCity.Text + "</city>" +
                                            "<county>" + cn.txtCounty.Text + "</county>" +
                                            "<state>" + cn.txtState.Text + "</state>" +
                                            "<zip-code>" + cn.txtZIPCode.Text + "</zip-code>";
    
                    xeCustumer.InnerXml = strCustumer;
                    xdCustumers.DocumentElement.PrependChild(xeCustumer);
    
                    using (FileStream fsCustumers = new FileStream(fiCustomers.FullName, FileMode.OpenOrCreate,
                                                                   FileAccess.Write, FileShare.Write))
                    {
                        xdCustumers.Save(fsCustumers);
                    }
                }
    
                ShowCustomers();
            }
    
            private void btnCustomerEditor_Click(object sender, EventArgs e)
            {
                CustomerEditor ce = new CustomerEditor();
    
                if( ce.ShowDialog() == DialogResult.OK)
                {
                    if (string.IsNullOrEmpty(ce.txtAccountNumber.Text))
                        return;
    
                    if (string.IsNullOrEmpty(ce.txtMeterNumber.Text))
                        return;
    
                    XmlNode xnExisting = null;
    
                    XmlDocument xdCustomers = new XmlDocument();
                    string strCustomers = "../../Customers.xml";
                    FileInfo fiCustomers = new FileInfo(strCustomers);
    
                    if (fiCustomers.Exists == true)
                    {
                        using (FileStream fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open,
                                                                       FileAccess.Read, FileShare.Read))
                        {
                            xdCustomers.Load(fsCustomers);
    
                            XmlNodeList xnlCustomers = xdCustomers.DocumentElement.ChildNodes;
    
                            foreach (XmlNode xnCustomer in xnlCustomers)
                            {
                                foreach (XmlNode xnAccountNumber in xnCustomer.ChildNodes)
                                {
                                    if (xnAccountNumber.InnerText == ce.txtAccountNumber.Text)
                                    {
                                        xnExisting = xnCustomer;
                                        break;
                                    }
                                }
                            }
                        }
                    }
    
                    XmlElement xeUpdatedCustomer = xdCustomers.CreateElement("customer");
    
                    string strUpdatedCustomer = "<account-number>" + ce.txtAccountNumber.Text + "</account-number>" +
                                                "<meter-number>" + ce.txtMeterNumber.Text + "</meter-number>" +
                                                "<first-name>" + ce.txtFirstName.Text + "</first-name>" +
                                                "<last-name>" + ce.txtLastName.Text + "</last-name>" +
                                                "<address>" + ce.txtAddress.Text + "</address>" +
                                                "<city>" + ce.txtCity.Text + "</city>" +
                                                "<county>" + ce.txtCounty.Text + "</county>" +
                                                "<state>" + ce.txtState.Text + "</state>" +
                                                "<zip-code>" + ce.txtZIPCode.Text + "</zip-code>";
    
                    xeUpdatedCustomer.InnerXml = strUpdatedCustomer;
    
                    xdCustomers.DocumentElement.ReplaceChild(xeUpdatedCustomer, xnExisting);
    
                    using (FileStream fsCustomers = new FileStream(fiCustomers.FullName, FileMode.OpenOrCreate,
                                                                   FileAccess.ReadWrite, FileShare.ReadWrite))
                    {
                        xdCustomers.Save(fsCustomers);
                    }
                }
    
                ShowCustomers();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  41. To create a new form, on the Solution Explorer, right-click WaterDistributionCompany -> Add -> Form (Windows Forms)...
  42. Change the file Name to BillPreparation
  43. Click Add
  44. To create a new form, on the main menu, click Project -> Add Form (Windows Forms)...
  45. Change the file name to BillEditor
  46. Click Add
  47. Click the BillPreparation.cs [Design] tab to return to the Bill Preparation form
  48. Design the form as follows:

    Using the Siblings of an XML Node

    Control (Name) Text Other Properties
    Label   Customer Account Information Font: Microsoft Sans Serif, 9.75pt, style=Bold
    Label   Account #:  
    TextBox txtAccountNumber    
    Label   Customer Name:  
    TextBox txtCustomerName    
    TextBox txtAddress    
    TextBox txtCity    
    TextBox: txtCounty    
    TextBox txtState    
    TextBox txtZIPCode    
    Label   Meter Information Font: Microsoft Sans Serif, 9.75pt, style=Bold
    Label   Meter Details:  
    TextBox txtMeterNumber    
    TextBox txtMeterDetails    
    Label   Meter Reading  
    Label   ___________________  
    Label   Reading Start Date:  
    Label   Reading End Date:  
    MonthCalendar mcReadingStartDate  
    MonthCalendar mcReadingEndDate  
    Label   Counter Readiing Start:  
    TextBox txtCounterReadiingStart   TextAlign: Right
    Label   Counter Readiing End:  
    TextBox txtCounterReadiingEnd   TextAlign: Right
    Label   Number of Days:  
    TextBox txtNumberOfDays   TextAlign: Right
    Label   Total CCF:  
    TextBox txtTotalHCF   TextAlign: Right
    Label   Total Therms (CCF * 1.0367):  
    TextBox txtTotalTherms   TextAlign: Right
    Label   Bill Values Font: Microsoft Sans Serif, 9.75pt, style=Bold
    Label   Transportation Charges:  
    TextBox txtTransportationCharges   TextAlign: Right
    Label   Delivery Total:  
    TextBox txtDeliveryTotal   TextAlign: Right
    Label   Distrib. Adjust (*0.13086):  
    TextBox txtDistributionAdjustment   TextAlign: Right
    Label   Environmental Charges:  
    TextBox txtEnvironmentalCharges   TextAlign: Right
    Label   First 50 Therms (* 0.5269):  
    TextBox txtFirst50Therms   TextAlign: Right
    Label   Over 50 Therms (* 0.4995):  
    TextBox txtOver50Therms   TextAlign: Right
    Label Local/County Taxes:    
    TextBox txtLocalTaxes   RightAlign: Right
    Label   State Taxes:  
    TextBox txtStateTaxes    
    Label   Total Charges:  
    TextBox txtTotalCharges   RightAlign: Right
    Label   _________________________  
    Label   Payment Due Date:  
    TextBox txtPaymentDueDate   TextAlign: Right
    Label   Amount Due:  
    TextBox txtAmountDue   TextAlign: Right
    Label   Late Payment Due Date:  
    TextBox txtLatePaymentDueDate   TextAlign: Right
    Label   Late Payment Amount Due:  
    TextBox txtLatePaymentAmountDue   TextAlign: Right
    Label   ____________________________  
    Label   Bill #:  
    TextBox txtBillNumber   TextAlign: Right
    Button btnSaveGasBill Save Gas Bill  
    Button btnReviewGasBill Review Gas Bill...  
    Button btnClose Close  
  49. Double-click an unoccupied area of the form to access its Load event
  50. Return to the form and click the Account # text box
  51. In the Properties window, click the Events button Events
  52. In the Events section of the Properties window, double-click Leave
  53. Return to the form and double-click the Reading Start Date month calendar
  54. Return to the form and double-click the Reading End Date month calendar
  55. Return to the form and click the Counter Reading End text box
  56. In the Events section of the Properties window, double-click Leave
  57. Return to the form and double-click the Save Gas Bill button
  58. Return to the form and double-click the Review Gas Bill button
  59. Return to the form and double-click the Close button
  60. Change the document as follows:
    using System;
    using System.IO;
    using System.Xml;
    using System.Windows.Forms;
    
    namespace QuatroGasCompany1
    {
        public partial class BillPreparation : Form
        {
            public BillPreparation()
            {
                InitializeComponent();
            }
    
            private void BillPreparation_Load(object sender, EventArgs e)
            {
                Random rndBillNumber = new Random();
    
                txtBillNumber.Text = rndBillNumber.Next(100001, 999999).ToString();
            }
    
            private void txtAccountNumber_Leave(object sender, EventArgs e)
            {
                if (string.IsNullOrEmpty(txtAccountNumber.Text))
                    return;
    
                string fnCustumers = "../../Customers.xml";
                XmlDocument xdCustumers = new XmlDocument();
                FileInfo fiCustumers = new FileInfo(fnCustumers);
    
                if (fiCustumers.Exists == true)
                {
                    xdCustumers.Load(fnCustumers);
                    XmlElement xeCustumer = xdCustumers.DocumentElement;
                    XmlNodeList xnlCustumers = xeCustumer.ChildNodes;
    
                    foreach (XmlNode xnCustumer in xnlCustumers)
                    {
                        foreach (XmlNode xnAccount in xnCustumer.ChildNodes)
                        {
                            if (xnAccount.InnerText == txtAccountNumber.Text)
                            {
                                txtMeterNumber.Text = xnAccount.NextSibling.InnerText;
                                txtCustomerName.Text = xnAccount.NextSibling.NextSibling.InnerText + " " +
                                                       xnAccount.NextSibling.NextSibling.NextSibling.InnerText;
                                txtAddress.Text = xnAccount.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtCity.Text = xnAccount.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtCounty.Text = xnAccount.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtState.Text = xnAccount.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtZIPCode.Text = xnAccount.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                            }
                        }
                    }
                }
    
                string fnGasMeters = "../../GasMeters.xml";
                XmlDocument xdGasMeters = new XmlDocument();
    
                if (string.IsNullOrEmpty(txtMeterNumber.Text))
                    return;
    
                if (File.Exists(fnGasMeters))
                {
                    xdGasMeters.Load(fnGasMeters);
                    XmlElement xeGasMeter = xdGasMeters.DocumentElement;
                    XmlNodeList xnlGasMeters = xeGasMeter.ChildNodes;
    
                    foreach (XmlNode xnGasMeter in xnlGasMeters)
                    {
                        if (xnGasMeter.FirstChild.InnerText == txtMeterNumber.Text)
                        {
                            txtMeterDetails.Text = xnGasMeter.FirstChild.NextSibling.InnerText + " " + xnGasMeter.FirstChild.NextSibling.NextSibling.InnerText;
                            mcReadingStartDate.SelectionStart = DateTime.Parse(xnGasMeter.FirstChild.NextSibling.NextSibling.NextSibling.InnerText);
                            txtCounterReadingStart.Text = xnGasMeter.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                        }
                    }
                }
            }
    
            private void mcReadingStartDate_DateChanged(object sender, DateRangeEventArgs e)
            {
                DateTime dtStart = mcReadingStartDate.SelectionStart;
                DateTime dtEnd = mcReadingEndDate.SelectionStart;
                TimeSpan tsDays = dtEnd.Subtract(dtStart);
    
                txtNumberOfDays.Text = tsDays.Days.ToString();
    
                txtPaymentDueDate.Text = mcReadingEndDate.SelectionStart.AddDays(21).ToShortDateString();
                txtLatePaymentDueDate.Text = mcReadingEndDate.SelectionStart.AddMonths(1).ToShortDateString();
            }
    
            private void mcReadingEndDate_DateChanged(object sender, DateRangeEventArgs e)
            {
                mcReadingStartDate_DateChanged(sender, e);
            }
    
            private void txtCounterReadingEnd_Leave(object sender, EventArgs e)
            {
                if (string.IsNullOrEmpty(txtAccountNumber.Text))
                {
                    MessageBox.Show("You must enter the starting value of the counter reading.",
                                    "Quatro Gas Company");
                    return;
                }
    
                if (string.IsNullOrEmpty(txtMeterNumber.Text))
                {
                    MessageBox.Show("You must enter the meter number of the gas meter used by " +
                                    "the customer (normally, this is done by entering the customer's account number).",
                                    "Quatro Gas Company");
                    return;
                }
    
                if (string.IsNullOrEmpty(txtCounterReadingEnd.Text))
                {
                    MessageBox.Show("You must enter the ending value of the counter reading.",
                                    "Quatro Gas Company");
                    return;
                }
    
                int meterReadingStart = int.Parse(txtCounterReadingStart.Text);
                int meterReadingEnd = int.Parse(txtCounterReadingEnd.Text);
    
                int consumption = meterReadingEnd - meterReadingStart;
    
                double totalTherms = consumption * 1.0367;
                double first50Therms, over50Therms;
    
                if (totalTherms < 50)
                {
                    first50Therms = totalTherms * 0.5269;
                    over50Therms = 0;
                }
                else
                {
                    first50Therms = 50 * 0.5269;
                    over50Therms = (totalTherms - 50) * 0.4995;
                }
    
                /* We will use some random values for the transportation charge (my 
                 * research didn't make it clear to me how gas companies set this price. */
                Random rndTransportation = new Random();
                double[] transportationValues = { 9.75, 9.95, 10.25, 10.45, 10.85, 12.55, 13.50, 14.35 };
    
                double transportationCharges = transportationValues[rndTransportation.Next(1, transportationValues.Length)];
                double deliveryTotal = transportationCharges + first50Therms + over50Therms;
    
                double distribution = totalTherms * 0.11086;
                double environment = deliveryTotal * 0.0045;
                double state = transportationCharges * 0.0225;
                double local = transportationCharges * 0.05826;
                double totalCharges = transportationCharges + deliveryTotal + distribution + environment + local + state;
                double amtDue = totalCharges;
    
                txtStateTaxes.Text = state.ToString("F");
                txtLocalTaxes.Text = local.ToString("F");
                txtAmountDue.Text = amtDue.ToString("F");
                txtCCFTotal.Text = consumption.ToString();
                txtTotalTherms.Text = totalTherms.ToString("F");
                txtOver50Therms.Text = over50Therms.ToString("F");
                txtTotalCharges.Text = totalCharges.ToString("F");
                txtFirst50Therms.Text = first50Therms.ToString("F");
                txtDeliveryTotal.Text = deliveryTotal.ToString("F");
                txtEnvironmentalCharges.Text = environment.ToString("F");
                txtDistributionAdjustment.Text = distribution.ToString("F");
                txtLatePaymentAmountDue.Text = (amtDue + 8.35).ToString("F");
                txtTransportationCharges.Text = transportationCharges.ToString("F");
            }
    
            private void btnSaveGasBill_Click(object sender, EventArgs e)
            {
                if (string.IsNullOrEmpty(txtAccountNumber.Text))
                {
                    MessageBox.Show("You must enter a (unique) account number for the customer." +
                                    Environment.NewLine +
                                    "We cannot create a customer account that doesn't have an account number.",
                                    "Gas Utility Company");
    
                    return;
                }
    
                if (string.IsNullOrEmpty(txtMeterNumber.Text))
                {
                    MessageBox.Show("You must type a (unique) number for the gas meter.", "Gas Utility Company");
    
                    return;
                }
    
                if (string.IsNullOrEmpty(txtCounterReadingEnd.Text))
                {
                    MessageBox.Show("You must type a the last number entered on the gas meter.", "Gas Utility Company");
    
                    return;
                }
    
                string strGasBills = "../../GasBills.xml";
                XmlDocument xdGasBills = new XmlDocument();
                FileInfo fiGasBills = new FileInfo(strGasBills);
    
                if (File.Exists(strGasBills))
                {
                    using (FileStream fsGasBills = new FileStream(fiGasBills.FullName, FileMode.Open,
                                                                  FileAccess.Read, FileShare.Read))
                    {
                        xdGasBills.Load(fsGasBills);
                    }
                }
                else
                {
                    xdGasBills.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                                       "<gas-bills></gas-bills>");
                }
    
                XmlElement xeGasBill = xdGasBills.CreateElement("gas-bill");
                string strGasBill    = "<bill-number>" + txtBillNumber.Text + "</bill-number>" +
                                       "<account-number>" + txtAccountNumber.Text + "</account-number>" +
                                       "<reading-start-date>" + mcReadingStartDate.SelectionStart.ToShortDateString() + "</reading-start-date>" +
                                       "<reading-end-date>" + mcReadingEndDate.SelectionStart.ToShortDateString() + "</reading-end-date>" +
                                       "<counter-reading-start>" + txtCounterReadingStart.Text + "</counter-reading-start>" +
                                       "<counter-reading-end>" + txtCounterReadingEnd.Text + "</counter-reading-end>" +
                                       "<number-of-days>" + txtNumberOfDays.Text + "</number-of-days>" +
                                       "<ccf-total>" + txtCCFTotal.Text + "</ccf-total>" +
                                       "<total-therms>" + txtTotalTherms.Text + "</total-therms>" +
                                       "<transportation-charges>" + txtTransportationCharges.Text + "</transportation-charges>" +
                                       "<delivery-total>" + txtDeliveryTotal.Text + "</delivery-total>" +
                                       "<distribution-adjustment>" + txtDistributionAdjustment.Text + "</distribution-adjustment>" +
                                       "<environmental-charges>" + txtEnvironmentalCharges.Text + "</environmental-charges>" +
                                       "<first-50-therms>" + txtFirst50Therms.Text + "</first-50-therms>" +
                                       "<over-50-therms>" + txtOver50Therms.Text + "</over-50-therms>" +
                                       "<local-taxes>" + txtLocalTaxes.Text + "</local-taxes>" +
                                       "<state-taxes>" + txtStateTaxes.Text + "</state-taxes>" +
                                       "<total-charges>" + txtTotalCharges.Text + "</total-charges>" +
                                       "<payment-due-date>" + txtPaymentDueDate.Text + "</payment-due-date>" +
                                       "<amount-due>" + txtAmountDue.Text + "</amount-due>" +
                                       "<late-payment-due-date>" + txtLatePaymentDueDate.Text + "</late-payment-due-date>" +
                                       "<late-payment-amount-due>" + txtLatePaymentAmountDue.Text + "</late-payment-amount-due>";
    
                xeGasBill.InnerXml = strGasBill;
                xdGasBills.DocumentElement.PrependChild(xeGasBill);
    
                using (FileStream fsGasBills = new FileStream(strGasBills, FileMode.OpenOrCreate,
                                                               FileAccess.Write, FileShare.Write))
                {
                    xdGasBills.Save(fsGasBills);
                }
    
                Close();
            }
    
            private void btnReviewGasBill_Click(object sender, EventArgs e)
            {
                BillEditor be = new BillEditor();
    
                be.ShowDialog();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  61. Click the BillEditor.cs [Design] tab to access its form
  62. Design the form as follows:

    Using the Siblings of an XML Node

    Control (Name) Text Other Properties
    Label   Customer Account Information Font: Microsoft Sans Serif, 9.75pt, style=Bold
    Label   Account #:  
    TextBox txtAccountNumber    
    Label   Customer Name:  
    TextBox txtCustomerName    
    TextBox txtAddress    
    TextBox txtCity    
    TextBox: txtCounty    
    TextBox txtState    
    TextBox txtZIPCode    
    Label   Meter Information Georgia, 9.75pt, style=Bold, Italic
    Label   Meter Details:  
    TextBox txtMeterNumber    
    TextBox txtMeterDetails    
    Label   Meter Reading  
    Label   ___________________  
    Label   Reading Start Date:  
    Label   Reading End Date:  
    MonthCalendar mcReadingStartDate  
    MonthCalendar mcReadingEndDate  
    Label   Counter Readiing Start:  
    TextBox txtCounterReadiingStart   TextAlign: Right
    Label   Counter Readiing End:  
    TextBox txtCounterReadiingEnd   TextAlign: Right
    Label   Number of Days:  
    TextBox txtNumberOfDays   TextAlign: Right
    Label   Total CCF:  
    TextBox txtTotalHCF   TextAlign: Right
    Label   Total Therms (CCF * 1.0367):  
    TextBox txtTotalTherms   TextAlign: Right
    Label   Bill Values Font: Microsoft Sans Serif, 9.75pt, style=Bold
    Label   Transportation Charges:  
    TextBox txtTransportationCharges   TextAlign: Right
    Label   Delivery Total:  
    TextBox txtDeliveryTotal   TextAlign: Right
    Label   Distrib. Adjust (*0.13086):  
    TextBox txtDistributionAdjustment   TextAlign: Right
    Label   Environmental Charges:  
    TextBox txtEnvironmentalCharges   TextAlign: Right
    Label   First 50 Therms (* 0.5269):  
    TextBox txtFirst50Therms   TextAlign: Right
    Label   Over 50 Therms (* 0.4995):  
    TextBox txtOver50Therms   TextAlign: Right
    Label   Local/County Taxes:  
    TextBox txtLocalTaxes   RightAlign: Right
    Label   State Taxes:  
    TextBox txtStateTaxes    
    Label   Total Charges:  
    TextBox txtTotalCharges   RightAlign: Right
    Label   _________________________  
    Label   Payment Due Date:  
    TextBox txtPaymentDueDate   TextAlign: Right
    Label   Amount Due:  
    TextBox txtAmountDue   TextAlign: Right
    Label   Late Payment Due Date:  
    TextBox txtLatePaymentDueDate   TextAlign: Right
    Label   Late Payment Amount Due:  
    TextBox txtLatePaymentAmountDue   TextAlign: Right
    Label   ____________________________  
    Label   Bill #:  
    TextBox txtBillNumber   TextAlign: Right
    Button btnOpenGasBill Open Gas Bill  
    Button btnSaveGasBill Save Gas Bill  
    Button btnClose Close  
  63. On the form, double-click the Open button
  64. Return to the form and double-click the Save Gaser Bill button
  65. Return to the form and double-click the Review Gas Bill button
  66. Return to the form and double-click the Close button
  67. Change the document as follows:
    using System;
    using System.IO;
    using System.Xml;
    using System.Windows.Forms;
    
    namespace QuatroGasCompany1
    {
        public partial class BillEditor : Form
        {
            public BillEditor()
            {
                InitializeComponent();
            }
    
            void IdentifyCustomer()
            {
                if (string.IsNullOrEmpty(txtAccountNumber.Text))
                    return;
    
                string fnCustumers = "../../Customers.xml";
                XmlDocument xdCustumers = new XmlDocument();
                FileInfo fiCustumers = new FileInfo(fnCustumers);
    
                if (fiCustumers.Exists == true)
                {
                    xdCustumers.Load(fnCustumers);
                    XmlElement xeCustumer = xdCustumers.DocumentElement;
                    XmlNodeList xnlCustumers = xeCustumer.ChildNodes;
    
                    foreach (XmlNode xnCustumer in xnlCustumers)
                    {
                        foreach (XmlNode xnAccount in xnCustumer.ChildNodes)
                        {
                            if (xnAccount.InnerText == txtAccountNumber.Text)
                            {
                                txtMeterNumber.Text = xnAccount.NextSibling.InnerText;
                                txtCustomerName.Text = xnAccount.NextSibling.NextSibling.InnerText + " " +
                                                       xnAccount.NextSibling.NextSibling.NextSibling.InnerText;
                                txtAddress.Text = xnAccount.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtCity.Text = xnAccount.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtCounty.Text = xnAccount.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtState.Text = xnAccount.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtZIPCode.Text = xnAccount.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
    
                                break;
                            }
                        }
                    }
                }
    
                string fnGasMeters = "../../GasMeters.xml";
                XmlDocument xdGasMeters = new XmlDocument();
    
                if (string.IsNullOrEmpty(txtMeterNumber.Text))
                    return;
    
                if (File.Exists(fnGasMeters))
                {
                    xdGasMeters.Load(fnGasMeters);
                    XmlElement xeGasMeter = xdGasMeters.DocumentElement;
                    XmlNodeList xnlGasMeters = xeGasMeter.ChildNodes;
    
                    foreach (XmlNode xnGasMeter in xnlGasMeters)
                    {
                        if (xnGasMeter.FirstChild.InnerText == txtMeterNumber.Text)
                        {
                            txtMeterDetails.Text = xnGasMeter.FirstChild.NextSibling.InnerText + " " + xnGasMeter.FirstChild.NextSibling.NextSibling.InnerText;
                            mcReadingStartDate.SelectionStart = DateTime.Parse(xnGasMeter.FirstChild.NextSibling.NextSibling.NextSibling.InnerText);
                            txtCounterReadingStart.Text = xnGasMeter.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
    
                            break;
                        }
                    }
                }
            }
    
            private void btnOpenGasBill_Click(object sender, EventArgs e)
            {
                string strGasBills = "../../GasBills.xml";
                XmlDocument xdGasBills = new XmlDocument();
                FileInfo fiGasBills = new FileInfo(strGasBills);
    
                if (File.Exists(strGasBills))
                {
                    using (FileStream fsGasBills = new FileStream(fiGasBills.FullName, FileMode.Open,
                                                                  FileAccess.Read, FileShare.Read))
                    {
                        xdGasBills.Load(fsGasBills);
                        XmlNodeList xnlGasBills = xdGasBills.DocumentElement.ChildNodes;
    
                        foreach (XmlNode xnGasBill in xnlGasBills)
                        {
                            if (xnGasBill.FirstChild.InnerText == txtBillNumber.Text)
                            {
                                txtAccountNumber.Text             =                xnGasBill.FirstChild.NextSibling.InnerText;// strAccountNumber;
                                mcReadingStartDate.SelectionStart = DateTime.Parse(xnGasBill.FirstChild.NextSibling.NextSibling.InnerText);
                                mcReadingEndDate.SelectionStart   = DateTime.Parse(xnGasBill.FirstChild.NextSibling.NextSibling.NextSibling.InnerText);
                                txtCounterReadingStart.Text       =                xnGasBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtCounterReadingEnd.Text         =                xnGasBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtNumberOfDays.Text              =                xnGasBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtCCFTotal.Text                  =                xnGasBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtTotalTherms.Text               =                xnGasBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtTransportationCharges.Text     =                xnGasBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtDeliveryTotal.Text             =                xnGasBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtDistributionAdjustment.Text    =                xnGasBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtEnvironmentalCharges.Text      =                xnGasBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtFirst50Therms.Text             =                xnGasBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtOver50Therms.Text              =                xnGasBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtLocalTaxes.Text                =                xnGasBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtStateTaxes.Text                =                xnGasBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtTotalCharges.Text              =                xnGasBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtPaymentDueDate.Text            =                xnGasBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtAmountDue.Text                 =                xnGasBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtLatePaymentDueDate.Text        =                xnGasBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
                                txtLatePaymentAmountDue.Text      =                xnGasBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
    
                                // break;
                            }
                        }
                    }
                }
    
                IdentifyCustomer();
            }
    
            private void btnSaveGasBill_Click(object sender, EventArgs e)
            {
                if( string.IsNullOrEmpty(txtBillNumber.Text))   
                    return;
                
                if (string.IsNullOrEmpty(txtAccountNumber.Text))    
                    return;
                
                XmlNode xnOriginalBill = null;
                
                XmlDocument xdGasBills = new XmlDocument();
                string strGasBills = "../../GasBills.xml";
                FileInfo fiGasBills = new FileInfo(strGasBills);
                
                if (fiGasBills.Exists == true)    
                {
                    using (FileStream fsGasBills = new FileStream(fiGasBills.FullName, FileMode.Open,
                                                                  FileAccess.Read, FileShare.Read))    
                    {
                        xdGasBills.Load(fsGasBills);
                        
                        XmlNodeList xnlGasBills = xdGasBills.DocumentElement.ChildNodes;
                        
                        foreach (XmlNode xnGasBill in xnlGasBills)    
                        {
                            foreach (XmlNode xnBillNumber in xnGasBill.ChildNodes)    
                            {
                                if(xnBillNumber.InnerText == txtBillNumber.Text)    
                                {
                                    xnOriginalBill = xnGasBill;
                                    break;    
                                }
                            }
                        }
                    }
                }
                
                XmlElement xeReviewedGasBill = xdGasBills.CreateElement("gas-bill");
                
                string strGasBill = "<bill-number>" + txtBillNumber.Text + "</bill-number>" +
                                    "<account-number>" + txtAccountNumber.Text + "</account-number>" +
                                    "<reading-start-date>" + mcReadingStartDate.SelectionStart.ToShortDateString() + "</reading-start-date>" +
                                    "<reading-end-date>" + mcReadingEndDate.SelectionStart.ToShortDateString() + "</reading-end-date>" +
                                    "<counter-reading-start>" + txtCounterReadingStart.Text + "</counter-reading-start>" +
                                    "<counter-reading-end>" + txtCounterReadingEnd.Text + "</counter-reading-end>" +
                                    "<number-of-days>" + txtNumberOfDays.Text + "</number-of-days>" +
                                    "<ccf-total>" + txtCCFTotal.Text + "</ccf-total>" +
                                    "<total-therms>" + txtTotalTherms.Text + "</total-therms>" +
                                    "<transportation-charges>" + txtTransportationCharges.Text + "</transportation-charges>" +
                                    "<delivery-total>" + txtDeliveryTotal.Text + "</delivery-total>" +
                                    "<distribution-adjustment>" + txtDistributionAdjustment.Text + "</distribution-adjustment>" +
                                    "<environmental-charges>" + txtEnvironmentalCharges.Text + "</environmental-charges>" +
                                    "<first-50-therms>" + txtFirst50Therms.Text + "</first-50-therms>" +
                                    "<over-50-therms>" + txtOver50Therms.Text + "</over-50-therms>" +
                                    "<local-taxes>" + txtLocalTaxes.Text + "</local-taxes>" +
                                    "<state-taxes>" + txtStateTaxes.Text + "</state-taxes>" +
                                    "<total-charges>" + txtTotalCharges.Text + "</total-charges>" +
                                    "<payment-due-date>" + txtPaymentDueDate.Text + "</payment-due-date>" +
                                    "<amount-due>" + txtAmountDue.Text + "</amount-due>" +
                                    "<late-payment-due-date>" + txtLatePaymentDueDate.Text + "</late-payment-due-date>" +
                                    "<late-payment-amount-due>" + txtLatePaymentAmountDue.Text + "</late-payment-amount-due>";
    
                xeReviewedGasBill.InnerXml = strGasBill;
    
                xdGasBills.DocumentElement.ReplaceChild(xeReviewedGasBill, xnOriginalBill);
                
                using (FileStream fsCustomers = new FileStream(fiGasBills.FullName, FileMode.OpenOrCreate,
                                                               FileAccess.ReadWrite, FileShare.ReadWrite))    
                {
                    xdGasBills.Save(fsCustomers);
                    
                }
    
                btnClose_Click(sender, e);
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  68. In the Solution Explorer, right-click Form1.cs and click Rename
  69. Type GasDistribution (to get WaterDistributionCompany.cs) and press Enter three times to display the form
  70. Design the form as follows:

    Water Distribution Company

    Control (Name) Text
    Button btnCustomers Customers...
    Button btnGasMeters Gas Meters...
    Button btnNewGasBill New Gas Bill...
    Button btnGasBillReview Gas Bill Review...
    Button btnClose Close
  71. On the form, double-click the Customers... button
  72. Return to the form and double-click the Gas Meters... button
  73. Return to the form and double-click the New Gas Bill... button
  74. Return to the form and double-click the Gas Bill Review... button
  75. Return to the form and double-click the Close button
  76. Change the document as follows:
    using System;
    using System.Windows.Forms;
    
    namespace QuatroGasCompany1
    {
        public partial class GasDistribution : Form
        {
            public GasDistribution()
            {
                InitializeComponent();
            }
    
            private void btnCustomers_Click(object sender, EventArgs e)
            {
                Customers clients = new Customers();
    
                clients.ShowDialog();
            }
    
            private void btnWaterMeters_Click(object sender, EventArgs e)
            {
                GasMeters wm = new GasMeters();
    
                wm.ShowDialog();
            }
    
            private void btnNewGasBill_Click(object sender, EventArgs e)
            {
                BillPreparation bp = new BillPreparation();
                bp.ShowDialog();
            }
    
            private void btnGasBillReview_Click(object sender, EventArgs e)
            {
                BillEditor be = new BillEditor();
                be.ShowDialog();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  77. To execute the project, on the main menu, click Debug -> Start Without Debugging:

    Getting an Item from a Collection

  78. Click the Water Meters button:

    Maintenance of XML Elements

  79. Close the Water Meters form
  80. Click the Customers button:

    Locating an Element Using its Name

  81. Click the New Customer button:

    Water for a Shining Life

  82. Type the values in the text boxes as in the following table. After each record, click the Save button:

    Account # Meter # First Name Last Name Address City County State ZIP Code
    2958-314-5294 392-44-572 Nicholas Thorn 2599 Phenicia Road Silver Spring Montgomery MD 20906
    8046-728-5060 304-861 Augustino Derbez 7507 Westchester Ave Washington   DC 20008
    4024-850-0482 820-418 Marianne Pattersen 10572 Maya Blvd Frederick Frederick MD 20111
    1848-205-3313 925-935 Frank Nounkeu 13931 Wellington Street College Park Pringe George MD 20740
    7029-371-8594 293-740 Danielle Dormand 2515 Guthierez Street Falls Church   VA 22046

    Locating an Element Using its Name

  83. Close the Customers form
  84. Click the green arrow to position the new bottle somwhere around the back side of the table:

    Modeling a Picnic Table

  85. Type the following values in the text boxes and select others from date time pickers:

    Water Bill # 294758
    Account # 7518-302-6895
    Service Start Date 10/5/2020
    Service End Date 1/12/2021
    Meter Reading Start 163
    Reading End 196

    Introducing Node Creation

  86. Click the Save Water Bill button
  87. Click the New Water Bill button again
  88. Set some values as follows:
    Water Bill # Account # Service Start Date: Service End Date Counter Reading Start Counter Reading End
    682048 4820-375-2842 10/22/2020 1/18/2021 109992 109998
    137579 2038-413-9680 10/22/2020 1/22/2021 137926 137975
    480465 9279-570-8394 11/14/2020 2/7/2021 6268 6275
    829736 7518-302-6895 1/12/2021 4/8/2021 114 118
  89. Close the forms and return to your programming environment
  90. Close the form and return to your programming environment
  91. Close your programming environment

Previous Copyright © 2005-2021, FunctionX Next