Application Setup

Introduction

Hi, for our exercise, we will create a text-based database Windows Forms application. We will us XML to store the records of our database.

Practical LearningPractical Learning: Introducing the Application

  1. Start Microsoft Visual Studio
  2. In the Visual Studion 2022 dialog box, click Create a New Project
  3. In the Create a New Project dialog box, in the languages combo box, select C#.
    In the list of projects templates, click Windows Forms App
  4. Click Next
  5. Change the Project Name to StellarWaterPoint1.
    Set the Location to a path of your choice
  6. Click Next
  7. In the Additional Information wizard page, in the Framework combo box, select the highest version (.NET 9.0 (Standard Term Support)
  8. Click Create

The Main Form of the Application

Our application will use a central form to access the other form. We will use the default form for that purpose. Our application will use records for water meters, customers, and water bills. Therefore, we will add some buttons for the forms related to those records.

Practical LearningPractical Learning: Preparing the Central Form of the Application

  1. In the Solution Explorer, right-click Form1.cs and click Rename
  2. Type WaterDistribution (to get WaterDistribution.cs) and press Enter
  3. Read the message on the message box and click Yes
  4. Click the body of the form to make sure it is selected.
    In the Properties window, change the following characteristics:
    Text: Stellar Water Point
    StartPosition: CenterScreen
    MaximizeBox: False
  5. Double-click an unoccupied area of the form to generate its Load event
  6. Impliment the event as follows:
    namespace StellarWaterPoint
    {
        public partial class WaterDistribution : Form
        {
            public WaterDistribution()
            {
                InitializeComponent();
            }
    
            private void WaterDistribution_Load(object sender, EventArgs e)
            {
                // If the directory for the database doesn't yet exist, create it
                Directory.CreateDirectory(@"C:\Stellar Water Point");
            }
        }
    }

Water Meters

Introduction

Our application will use forms to create water meter records, to view a record of a water meter, to edit or to delete the record of a water meter.

Practical LearningPractical Learning: Introducing Water Meters

  1. To create a folder, in the Solution Explorer, right-click the StellarWaterPoint1 project -> Add -> New Folder
  2. Type WaterMeters as the name of the folder

Displaying Water Meters

To let the user see a list of the water meters in the database, we will use a form equipped with a list view.

Practical LearningPractical Learning: Displaying Water Meters

  1. To create a form, in the Solution Explorer, right-click WaterMeters -> Add -> Form (Windows Forms)...
  2. TFor the Name of the form, type Central
  3. Click Add
  4. In the Toolbox, click the ListView button and click the form
  5. On the form, right-click the list view and click Edit Columns...
  6. Create the columns as follows:
    (Name) Text Width
    colWaterMeterId Id 40
    colMeterNumber Meter # 150
    colMake Make 300
    colModel Model 150
    colMeterSize Meter Size 150
  7. Click OK
  8. Position and resize the list view on the form as follows:

    Stellar Water Point - Water Meters

    Control (Name) Other Properties
    ListView List View lvwWaterMeters FullRowSelect: True
    GridLines: True
    View: Details
    Anchor: Top, Bottom, Left, Right
  9. Doubte-click an unoccupied area of the form to generate its Load event
  10. Change the document as follows:
    using System.Xml;
    
    namespace StellarWaterPoint1.WaterMeters
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
            private void ShowWaterMeters()
            {
                // Create a reference to the XML's DOM object
                XmlDocument xdWaterMeters = new XmlDocument();
                // Indicate the file that holds a list of water meters
                string strFileWaterMeters = @"C:\Stellar Water Point\WaterMeters.xml";
    
                // Check whether a file that holds a list of water meters exists
                if(File.Exists(strFileWaterMeters))
                {
                    // If that file exists, open it
                    using (FileStream fsWaterMeters = new FileStream(strFileWaterMeters, FileMode.Open,
                                                                     FileAccess.Read, FileShare.Read))
                    {
                        /* Get the list of water meters from the file and store
                         * the records in the previously created DOM object. */
                        xdWaterMeters.Load(fsWaterMeters);
    
                        /* If there is at least one record for the water meters, 
                         * create an XmlNodeList list and transmit it to 
                         * a ViewData collection that wille be used in the view page.*/
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.ChildNodes;
    
                        int id = 1;
    
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            ListViewItem lviWaterMeter = new ListViewItem(id++.ToString());
    
                            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);
    
                            lvwWaterMeters.Items.Add(lviWaterMeter);
                        }
                    }
                }
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                ShowWaterMeters();
            }
        }
    }
  11. In the Solution Explorer, double-click WaterDistribution.cs to display the main form of the application
  12. From the Toolbox, add a button to the form
  13. From the Properties window, change the characteristics of the button as follows:

    Stellar Water Point

    Control (Name) Text Font
    Button Button btnWaterMeters &Water Meters... Times New Roman, 24pt, style=Bold
  14. Double-click the &Water Meters button
  15. Impliment the event as follows:
    namespace StellarWaterPoint1
    {
        public partial class WaterDistribution : Form
        {
            public WaterDistribution()
            {
                InitializeComponent();
            }
    
            private void WaterDistribution_Load(object sender, EventArgs e)
            {
                // If the directory for the database doesn't yet exist, create it
                Directory.CreateDirectory(@"C:\Stellar Water Point");
            }
    
            private void btnWaterMeters_Click(object sender, EventArgs e)
            {
                WaterMeters.Central central = new WaterMeters.Central();
    
                central.ShowDialog();
            }
        }
    }

A Water Meter Record

Our application will have a list of water meters. A record for each water meter must be created. To make this happen, we will equip the application with an appropriate form.

Practical LearningPractical Learning: Creating a Water Meter Record

  1. To create a form, in the Solution Explorer, right-click the WaterMeters folder -> Add -> Form (Windows Forms)...
  2. For the Name of the file, type Create as the name of the form
  3. Click Add
  4. Design the form as follows:

    Stellar Water Point - New Water Meter

    Control (Name) Text Other Properties
    Label Label   &Meter #:  
    MaskedTextBox Masked Text Box mtbMeterNumber   Masked: 000-000-000
    Label Label   M&ake:  
    TextBox Text Box txtMake   Modifiers: Public
    Label Label   M&odel:  
    TextBox Text Box txtModel   Modifiers: Public
    Label Label   Me&ter Size:  
    TextBox Text Box txtMeterSize   Modifiers: Public
    Button Button btnOK &OK DialogResult: OK
    Button Button btnCancel &Cancel DialogResult: Cancel
  5. Using the Properties window, change some characteristics of the form as follows:
    FormBorderStyle: FixedDialog
    Text:            Stellar Water Point - Water Meter Setup
    StartPosition:   CenterScreen
    AcceptButton:    btnOK
    CancelButton:    btnCancel
  6. In the Solution Explorer, below the WaterMeters folder, double-click Central.cs
  7. From the Toolbox, add a button to the form below the list view
  8. Change the characteristics of the button as follows:

    Stellar Water Point - Water Meters

    Control (Name) Other Properties
    ListView List View lvwWaterMeters FullRowSelect: True
    GridLines: True
    View: Details
    Anchor: Top, Bottom, Left, Right
    Button Button btnNewWaterMeter &New Water Meter...
    Anchor: Bottom, Right
  9. On the Central form, double-click the New Water Meter button
  10. Implement the event as follows:
    using System.Xml;
    
    namespace StellarWaterPoint10.WaterMeters
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowWaterMeters()
            {
                // Create an XML Dom reference
                XmlDocument xdWaterMeters = new XmlDocument();
                // Declare a string variable to have the file that holds a list of water meters
                string? strWaterMeters = @"C:\Stellar Water Point\WaterMeters.xml";
    
                // Create a FileInfo object that holds a reference to the file of water meters
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                // If you are about to display a list of water meters, first empty the list view
                lvwWaterMeters.Items.Clear();
    
                // Check whether a file for water meters was previously created.
                if (fiWaterMeters.Exists)
                {
                    // If such a file exists, create a Stream for it
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        // Store the stream of water meters into the XML Dom that was created earlier
                        xdWaterMeters.Load(fsWaterMeters);
                        // Get a list of the water meter elements from the XML Dom object
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.ChildNodes;
    
                        int i = 1;
    
                        lvwWaterMeters.Items.Clear();
    
                        // Check each water meter
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            // Create a list view item to hold a record of a water meter
                            ListViewItem lviWaterMeter = new ListViewItem(i.ToString());
    
                            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);
    
                            // Pass the list view item to the list view object on the form
                            lvwWaterMeters.Items.Add(lviWaterMeter);
    
                            i++;
                        }
                    }
                }
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                // When the open opens, make an attempt to display a list of water meters.
                ShowWaterMeters();
            }
    
            private void btnNewWaterMeter_Click(object sender, EventArgs e)
            {
                // Get a reference to the form used to add a water meter
                Create wm = new();
                // Create a FileInfo object
                FileInfo? fiWaterMeters = null;
                // Create a file stream object
                FileStream? fsWaterMeters = null;
                // Create an XML Dom object
                XmlDocument xdWaterMeters = new XmlDocument();
                // Declare a string for a file to hold a list of water meters
                string? strWaterMeters = @"C:\Stellar Water Point\WaterMeters.xml";
    
                /* Display the form used to create a water meter. 
                 * If the user finishes using that form and click the OK button... */
                if (wm.ShowDialog() == DialogResult.OK)
                {
                    // Store the file of water meters into the FileInfo object that was previously created.
                    fiWaterMeters = new FileInfo(strWaterMeters);
    
                    /* Find out whether a list of water meters was previously created 
                     * and was stored in the string file declared above. */
                    if (fiWaterMeters.Exists)
                    {
                        /* If that file exists already, create a Stream object 
                         * for it with a read-only status. */
                        using (fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open,
                                                              FileAccess.Read, FileShare.Read))
                        {
                            // Pass the list of water meters to the XML Dom object created earlier
                            xdWaterMeters.Load(fsWaterMeters);
                        }
                    }
                    else
                    {
                        // If a file for water meters was not previously created, create it now...
                        using (fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Create,
                                                              FileAccess.Write, FileShare.Write))
                        {
                            // and create the root XML element for it
                            xdWaterMeters.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                                                  "<water-meters></water-meters>");
                            // Make sure you save the new file
                            xdWaterMeters.Save(fsWaterMeters);
                        }
                    }
    
                    // Now that the file exists, open it
                    using (fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.OpenOrCreate, 
                                                          FileAccess.ReadWrite, FileShare.ReadWrite))
                    {
                        // Start creating a new Water Meter XML element
                        XmlElement xeWaterMeter = xdWaterMeters.CreateElement("water-meter");
    
                        /* Use the values that the user had typed in the Create form.
                         * Use those values to create the child elements of the new water meter node.
                         * Assign the combination of child elements to the new water meter node. */
                        xeWaterMeter.InnerXml = "<meter-number>" + wm.mtbMeterNumber.Text + "</meter-number>" +
                                                "<make>" + wm.txtMake.Text + "</make>" +
                                                "<model>" + wm.txtModel.Text + "</model>" +
                                                "<meter-size>" + wm.txtMeterSize.Text + "</meter-size>";
                        // Once the XML element is ready, add/append it to the XML Dom that was previously created.
                        xdWaterMeters.DocumentElement!.AppendChild(xeWaterMeter);
                        // Once the new element has been created and add it to the file, save that file
                        xdWaterMeters.Save(fsWaterMeters);
                    }
                }
    
                /* Whenever the user has finished using the Create form, 
                 * make an attempt to display the list of water meters. */
                ShowWaterMeters();
            }
        }
    }
  11. To execute the application, on the main menu, click Debug -> Start Without Debugging

    Stellar Water Point

  12. On the Central form, click the Water Meters button:

    Stellar Water Point - Water Meters

  13. Click the New Water Meter button:

    Stellar Water Point - New Water Meter

  14. Enter the value for each of the following records and click OK (or press Enter) for each:
    Meter # Make Model Meter Size
    392-494-572 Constance Technologies TG-4822 5/8 Inches
    938-705-869 Stan Wood 66-G 1 Inch
    588-279-663 Estellano NCF-226 3/4 Inches

    Stellar Water Point - Water Meters

  15. Close the forms and return to your programming environment

Water Meter Details

Once a database exists, sometimes a use mmay want to check the values of a water meter record. To support this, we will add an appropriate form to our application.

Practical LearningPractical Learning: Creating a Water Meter Record

  1. To create a form, in the Solution Explorer, right-click WaterMeters -> Add -> Form (Windows Forms)...
  2. For the Name of the form, type Details
  3. Press Enter
  4. Resize the Editor form to have the same size as the Create form
  5. Copy everything from the Create form and paste it in the Editor form
  6. Delete the bottom two buttons and add a new button
  7. Change the design of the form as follows:

    Stellar Water Point - New Water Meter

    Control (Name) Text
    Button Button btnFindWateMeter &Find Water Meter
    Button Button btnClose &Close
  8. On the form, double-click the Find button
  9. Return to the form and double-click the Close button
  10. Change the document as follows:
    using System.Xml;
    
    namespace StellarWaterPoint10.WaterMeters
    {
        public partial class Details : Form
        {
            public Details()
            {
                InitializeComponent();
            }
    
            private void btnFindWateMeter_Click(object sender, EventArgs e)
            {
                /* If the user clicks the Find button, 
                 * make sure there is a meter number in the top text box. */
                if (string.IsNullOrEmpty(mtbMeterNumber.Text))
                {
                    /* If the user didn't type a meter number, 
                     * display a message box to inform the user. */
                    MessageBox.Show("You must type a meter number and then click the Find button.",
                                    "Stellar Water Point", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    // If the user didn't type a meter number but clicked Find, don't do anything
                    return;
                }
    
                // We will need a reference to an XML Dom object as an XmlDocument variable
                XmlDocument xdWaterMeters = new XmlDocument();
                // This is the name and path of the file that holds the records of water meters
                string? strWaterMeters = @"C:\Stellar Water Point\WaterMeters.xml";
                // We will process the file of water meters using a FileInfo object
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                // We need to find out whether a file for water meters was previously created.
                if (fiWaterMeters.Exists)
                {
                    // If that file exists, create a stream of it. Open that file with a read-only status
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        // Get the list of water meter records and put those records in the XML Dom object created earlier.
                        xdWaterMeters.Load(fsWaterMeters);
                        /* Use XPath to locate the water meter that has 
                         * the same meter number as the one in the Meter # text box.
                         * Store the water meter in an XmlNodeList variable. */
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + mtbMeterNumber.Text + "']")!;
    
                        /* If there is a water meter in the database with 
                         * the number that the user typed, locate that water meter 
                         * and display each of its values in the appropriate text box. */
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            txtMake.Text = xnWaterMeter.NextSibling!.InnerText;
                            txtModel.Text = xnWaterMeter.NextSibling.NextSibling!.InnerText;
                            txtMeterSize.Text = xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText;
                        }
                    }
                }
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  11. In the Solution Explorer, below the WaterMeters folder, double-click Central.cs to open its form
  12. On the form, click the list view
  13. In the Properties window, click the Events button Events
  14. In the Events section of the Properties window, double-click DoubleClick
  15. Implement the event as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.WaterMeters
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
            
            . . .
    
            private void lvwWaterMeters_DoubleClick(object sender, EventArgs e)
            {
                if(lvwWaterMeters.SelectedItems.Count > 0)
                {
                    Details details = new();
    
                    details.mtbMeterNumber.Text = lvwWaterMeters.SelectedItems[0].SubItems[1].Text;
    
                    XmlDocument xdWaterMeters = new XmlDocument();
                    string? strWaterMeters = @"C:\Stellar Water Point\WaterMeters.xml";
                    FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                    if (fiWaterMeters.Exists)
                    {
                        using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                        {
                            xdWaterMeters.Load(fsWaterMeters);
                            XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + lvwWaterMeters.SelectedItems[0].SubItems[1].Text + "']")!;
    
                            foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                            {
                                details.txtMake.Text = xnWaterMeter.NextSibling!.InnerText;
                                details.txtModel.Text = xnWaterMeter.NextSibling.NextSibling!.InnerText;
                                details.txtMeterSize.Text = xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText;
                            }
                        }
                    }
    
                    details.ShowDialog();
                }
            }
        }
    }
  16. Return to the form
  17. From the Toolbox, add a button to the form below the list view and to the right of the New Water Meter button
  18. Change the characteristics of the button as follows:

    Stellar Water Point - Water Meters

    Control (Name) Other Properties
    ListView List View lvwWaterMeters No Change
    Button Button btnNewWaterMeter &New Water Meter...
    Anchor: Bottom, Right
    Button Button btnViewWaterMeter &View Water Meter...
    Anchor: Bottom, Right
  19. Double-click the View Water Meter button
  20. Change the document as follows:
    using System.Xml;
    
    namespace StellarWaterPoint1.WaterMeters
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowWaterMeters()
            {
                . . .
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                // When the open opens, make an attempt to display a list of water meters.
                ShowWaterMeters();
            }
    
            private void btnNewWaterMeter_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void lvwWaterMeters_DoubleClick(object sender, EventArgs e)
            {
                if(lvwWaterMeters.SelectedItems.Count > 0)
                {
                    Details details = new();
    
                    details.mtbMeterNumber.Text = lvwWaterMeters.SelectedItems[0].SubItems[1].Text;
    
                    XmlDocument xdWaterMeters = new XmlDocument();
                    string? strWaterMeters = @"C:\Stellar Water Point\WaterMeters.xml";
                    FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                    if (fiWaterMeters.Exists)
                    {
                        using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                        {
                            xdWaterMeters.Load(fsWaterMeters);
                            XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + lvwWaterMeters.SelectedItems[0].SubItems[1].Text + "']")!;
    
                            foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                            {
                                details.txtMake.Text = xnWaterMeter.NextSibling!.InnerText;
                                details.txtModel.Text = xnWaterMeter.NextSibling.NextSibling!.InnerText;
                                details.txtMeterSize.Text = xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText;
                            }
                        }
                    }
    
                    details.ShowDialog();
                }
            }
    
            private void btnViewWaterMeter_Click(object sender, EventArgs e)
            {
                /* Get a reference to the dialog box that is used 
                 * to view information about a water meter. */
                Details view = new();
                // Display that dialog box
                view.ShowDialog();
    
                // After using the dialog box, make an attempt to display the list of water meters.
                ShowWaterMeters();
            }
        }
    }
  21. To execute the application, on the main menu, click Debug -> Start Without Debugging

    Stellar Water Point

  22. On the Water Distribution form, click the Water Meters button
  23. On the Central form of water meters, click the View Water Meter button:

    Stellar Water Point - View Water Meter

  24. In the Meter # text, type 392-494-572
  25. Click the Find button:

    Stellar Water Point - View Water Meter

  26. Close the Details form
  27. On the Water Meters form, double-click the third record
  28. Close the forms and return to your programming environment

Updating a Water Meter Details

One of the routine operations performed on a database is to change the details of a record. To support this operation for a water meter, we will create a form that can be used to update the information of a water meter.

Practical LearningPractical Learning: Updating a Water Meter

  1. To create a form, in the Solution Explorer, right-click WaterMeters -> Add -> Form (Windows Forms)...
  2. For the Name of the file, type Editor as the name of the form
  3. Click Add
  4. Resize the Editor form to have the same size as the Details form
  5. Copy everything from the Details form and paste it in the Editor form
  6. Change the design of the form as follows:

    Stellar Water Point - New Water Meter

    Control (Name) Text
    Button Button btnUpdateWateMeter &Update Water Meter
  7. On the form, double-click the Find button
  8. Change the document as follows:
    using System.Xml;
    
    namespace StellarWaterPoint1.WaterMeters
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void btnFind_Click(object sender, EventArgs e)
            {
                XmlDocument xdWaterMeters = new XmlDocument();
                string? strWaterMeters = @"C:\Stellar Water Point\WaterMeters.xml";
    
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                if (fiWaterMeters.Exists)
                {
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdWaterMeters.Load(fsWaterMeters);
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + mtbMeterNumber.Text + "']")!;
    
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            txtMake.Text = xnWaterMeter.NextSibling!.InnerText;
                            txtModel.Text = xnWaterMeter.NextSibling.NextSibling!.InnerText;
                            txtMeterSize.Text = xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText;
                        }
                    }
                }
            }
        }
    }
  9. Return to the form and double-click the Update Water Meter button
  10. Change the document as follows:
    using System.Xml;
    
    namespace StellarWaterPoint1.WaterMeters
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            . . .
    
            private void btnUpdateWaterMeter_Click(object sender, EventArgs e)
            {
                XmlDocument xdWaterMeters = new XmlDocument();
                string? strWaterMeters = @"C:\Stellar Water Point\WaterMeters.xml";
    
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                if (fiWaterMeters.Exists)
                {
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdWaterMeters.Load(fsWaterMeters);
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + mtbMeterNumber.Text + "']")!;
    
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            xnWaterMeter.ParentNode!.InnerXml = "<meter-number>" + mtbMeterNumber.Text + "</meter-number>" +
                                                                "<make>" + txtMake.Text + "</make>" +
                                                                "<model>" + txtModel.Text + "</model>" +
                                                                "<meter-size>" + txtMeterSize.Text + "</meter-size>";
                        }
                    }
    
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
                    {
                        xdWaterMeters.Save(fsWaterMeters);
                    }
                }
    
                Close();
            }
        }
    }
  11. Return to the form and double-click the Close button
  12. Change the document as follows:
    using System.Xml;
    
    namespace StellarWaterPoint10.WaterMeters
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void btnFindWateMeter_Click(object sender, EventArgs e)
            {
                /* If the user clicks the Find button, 
                 * make sure there is a meter number in the top text box. */
                if (string.IsNullOrEmpty(mtbMeterNumber.Text))
                {
                    /* If the user didn't type a meter number, 
                     * display a message box to inform the user. */
                    MessageBox.Show("You must type a meter number and then click the Find button.",
                                    "Stellar Water Point", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    // If the user didn't type a meter number but clicked Find, don't do anything
                    return;
                }
    
                // We will need a reference to an XML Dom object as an XmlDocument variable
                XmlDocument xdWaterMeters = new XmlDocument();
                // This is the name and path of the file that holds the records of water meters
                string? strWaterMeters = @"C:\Stellar Water Point\WaterMeters.xml";
                // We will process the file of water meters using a FileInfo object
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                // We need to find out whether a file for water meters was previously created.
                if (fiWaterMeters.Exists)
                {
                    // If that file exists, create a stream of it. Open that file with a read-only status
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        /* Get the list of water meter records 
                         * and put those records in the XML Dom object created earlier. */
                        xdWaterMeters.Load(fsWaterMeters);
                        /* Use XPath to locate the water meter that has 
                         * the same meter number as the one in the Meter # text box.
                         * Store the water meter in an XmlNodeList variable. */
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + mtbMeterNumber.Text + "']")!;
    
                        /* If there is a water meter in the database with 
                         * the number that the user typed, locate that water meter 
                         * and display each of its values in the appropriate text box. */
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            txtMake.Text = xnWaterMeter.NextSibling!.InnerText;
                            txtModel.Text = xnWaterMeter.NextSibling.NextSibling!.InnerText;
                            txtMeterSize.Text = xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText;
                        }
                    }
                }
            }
    
            private void btnUpdateWaterMeter_Click(object sender, EventArgs e)
            {
                // We will need a reference to an XML Dom object as an XmlDocument variable
                XmlDocument xdWaterMeters = new();
                // This is the name and path of the file that holds the records of water meters
                string? strWaterMeters = @"C:\Stellar Water Point\WaterMeters.xml";
                // We will process the file of water meters using a FileInfo object
                FileInfo? fiWaterMeters = new(strWaterMeters);
    
                // We need to find out whether a file for water meters was previously created.
                if (fiWaterMeters.Exists)
                {
                    // If that file exists, create a stream of it. Open that file with a read-only status
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        /* Get the list of water meter records 
                         * and put those records in the XML Dom object created earlier. */
                        xdWaterMeters.Load(fsWaterMeters);
                        /* Use XPath to locate the water meter that has 
                         * the same meter number as the one in the Meter # text box.
                         * Store the water meter in an XmlNodeList variable. */
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + mtbMeterNumber.Text + "']")!;
    
                        // Check each record of the water meters.
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            /* If you find a record whose water meter is 
                             * the same as the meter number that the user typed,
                             * change the values of the Make, the Model, 
                             * and the Meter Size based on the values 
                             * the user typed in the corresponding text boxes. */
                            xnWaterMeter.ParentNode!.InnerXml = "<meter-number>" + mtbMeterNumber.Text + "</meter-number>" +
                                                                "<make>" + txtMake.Text + "</make>" +
                                                                "<model>" + txtModel.Text + "</model>" +
                                                                "<meter-size>" + txtMeterSize.Text + "</meter-size>";
                        }
                    }
    
                    /* Now that a water meter has been changed/update 
                     * (and the file of water meters has changed), save the new version of the file. */
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
                    {
                        xdWaterMeters.Save(fsWaterMeters);
                    }
                }
    
                /* If the user has updated a record, we will assume that, 
                 * in most cases (such as usually in real life), 
                 * a user updates one record and moves to other activities.
                 * For this record, after the user has updated a record, 
                 * we will clode the form. */
                Close();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  13. In the Solution Explorer, below the WaterMeters folder, double-click Central.cs
  14. From the Toolbox, add a button to the form below the list view and on the right side of the View Water Meter button
  15. Change the characteristics of the button as follows:

    Stellar Water Point - Water Meters

    Control (Name) Other Properties
    ListView List View lvwWaterMeters FullRowSelect: True
    GridLines: True
    View: Details
    Anchor: Top, Bottom, Left, Right
    Button Button btnNewWaterMeter &New Water Meter...
    Anchor: Bottom, Right
    Button Button btnViewWaterMeter &View Water Meter...
    Anchor: Bottom, Right
    Button Button btnEditWaterMeter &Edit Water Meter...
    Anchor: Bottom, Right
  16. Display the Central form of the WaterMeters folder
  17. Double-click the Update Water Meter button
  18. Change the document as follows:
    using System.Xml;
    
    namespace StellarWaterPoint1.WaterMeters
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowWaterMeters()
            {
                . . .
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                // When the open opens, make an attempt to display a list of water meters.
                ShowWaterMeters();
            }
    
            private void btnNewWaterMeter_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void btnViewWaterMeter_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void btnEditWaterMeter_Click(object sender, EventArgs e)
            {
                /* Get a reference to the dialog box that is used 
                 * to update the details of a water meter. */
                Editor editor = new();
                // Display that dialog box
                editor.ShowDialog();
    
                // After using the dialog box, make an attempt to display the list of water meters.
                ShowWaterMeters();
            }
        }
    }
  19. To execute the application, on the main menu, click Debug -> Start Without Debugging
  20. On the Central form, click the Water Meters button
  21. Click the Edit Water Meter button:

    Stellar Water Point - Water Meter Editor

  22. In the Meter # text, type 938-705-869
  23. Click the Find button

    Stellar Water Point - Water Meter Editor

  24. Change the values as follows:
    Make: Stanford Trend
    Model: 266G
    Meter Size: 1 1/2 Inches

    Stellar Water Point - New Water Meter

  25. Click the Update button:

    Stellar Water Point - Water Meters

  26. Close the forms and return to your programming environment

Removing a Water Meter from the Database

If a record is not necessary anymore on a database, the user may want to remove it. To assist the user with this operation, we will create a form withe necessary buttons.

Practical LearningPractical Learning: Deleting a Water Meter Record

  1. To create a form, in the Solution Explorer, right-click WaterMeters -> Add -> Form(Windows Forms)...
  2. In the Name text box, replace the string with Delete as the name of the form
  3. Press Enter
  4. Resize the Delete form to have the same size as the Editor form
  5. Copy everything from the Editor form and paste it in the Delete form
  6. Change the bottom button as follows:

    Stellar Water Point - New Water Meter

    Control (Name) Text
    Button Button btnDeleteWateMeter &Delete Water Meter
  7. On the form, double-click the Find Water Meter button
  8. Change the document as tollows:
    using System.Xml;
    
    namespace StellarWaterPoint1.WaterMeters
    {
        public partial class Delete : Form
        {
            public Delete()
            {
                InitializeComponent();
            }
    
            private void btnFind_Click(object sender, EventArgs e)
            {
                XmlDocument xdWaterMeters = new XmlDocument();
                string? strWaterMeters = @"C:\Stellar Water Point\WaterMeters.xml";
    
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                if (fiWaterMeters.Exists)
                {
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdWaterMeters.Load(fsWaterMeters);
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + mtbMeterNumber.Text + "']")!;
    
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            txtMake.Text = xnWaterMeter.NextSibling!.InnerText;
                            txtModel.Text = xnWaterMeter.NextSibling.NextSibling!.InnerText;
                            txtMeterSize.Text = xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText;
                        }
                    }
                }
            }
        }
    }
  9. Return to the form and double-click the Delete Water Meter button
  10. Change the document as tollows:
    using System.Xml;
    
    namespace StellarWaterPoint1.WaterMeters
    {
        public partial class Delete : Form
        {
            public Delete()
            {
                InitializeComponent();
            }
    
            . . .
    
            private void btnDeleteWaterMeter_Click(object sender, EventArgs e)
            {
                XmlDocument xdWaterMeters = new XmlDocument();
                string? strWaterMeters = @"C:\Stellar Water Point\WaterMeters.xml";
    
                if (string.IsNullOrEmpty(mtbMeterNumber.Text))
                {
                    MessageBox.Show("You must type a water meter number if you want to delete one.",
                                    "Stellar Water Point", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }
    
                if (!File.Exists(strWaterMeters))
                {
                    MessageBox.Show("There is no file for the water meters in the system.",
                                    "Stellar Water Point",
                                    MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }
    
                xdWaterMeters.Load(strWaterMeters);
    
                XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.GetElementsByTagName("meter-number");
    
                foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                {
                    if (xnWaterMeter.InnerText == mtbMeterNumber.Text)
                    {
                        if (MessageBox.Show("Are you sure you want to delete this water meter record from the system?",
                                        "Stellar Water Point",
                                        MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                        {
                            xdWaterMeters.DocumentElement.RemoveChild(xnWaterMeter.ParentNode!);
                            break;
                        }
                    }
                }
    
                xdWaterMeters.Save(strWaterMeters);
    
                Close();
            }
        }
    }
  11. Return to the form and double-click the Close button
  12. Change the document as tollows:
    using System.Xml;
    
    namespace StellarWaterPoint10.WaterMeters
    {
        public partial class Delete : Form
        {
            public Delete()
            {
                InitializeComponent();
            }
    
            private void btnFindWateMeter_Click(object sender, EventArgs e)
            {
                /* If the user clicks the Find button, 
                 * make sure there is a meter number in the top text box. */
                if (string.IsNullOrEmpty(mtbMeterNumber.Text))
                {
                    /* If the user didn't type a meter number, 
                     * display a message box to inform the user. */
                    MessageBox.Show("You must type a meter number and then click the Find button.",
                                    "Stellar Water Point", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    // If the user didn't type a meter number but clicked Find, don't do anything
                    return;
                }
    
                // We will need a reference to an XML Dom object as an XmlDocument variable
                XmlDocument xdWaterMeters = new XmlDocument();
                // This is the name and path of the file that holds the records of water meters
                string? strWaterMeters = @"C:\Stellar Water Point\WaterMeters.xml";
                // We will process the file of water meters using a FileInfo object
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                // We need to find out whether a file for water meters was previously created.
                if (fiWaterMeters.Exists)
                {
                    // If that file exists, create a stream of it. Open that file with a read-only status
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        /* Get the list of water meter records 
                         * and put those records in the XML Dom object created earlier. */
                        xdWaterMeters.Load(fsWaterMeters);
                        /* Use XPath to locate the water meter that has 
                         * the same meter number as the one in the Meter # text box.
                         * Store the water meter in an XmlNodeList variable. */
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + mtbMeterNumber.Text + "']")!;
    
                        /* If there is a water meter in the database with 
                         * the number that the user typed, locate that water meter 
                         * and display each of its values in the appropriate text box. */
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            txtMake.Text = xnWaterMeter.NextSibling!.InnerText;
                            txtModel.Text = xnWaterMeter.NextSibling.NextSibling!.InnerText;
                            txtMeterSize.Text = xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText;
                        }
                    }
                }
            }
    
            private void btnDeleteWaterMeter_Click(object sender, EventArgs e)
            {
                /* If the user clicks the Delete button, make sure that 
                 * the right text box contains a meter number */
                if (string.IsNullOrEmpty(mtbMeterNumber.Text))
                {
                    // If the user didn't provide a meter number, display a message box ...
                    MessageBox.Show("You must type a water meter number if you want to delete one.",
                                    "Stellar Water Point", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    // .. and stop the operation.
                    return;
                }
    
                // Create an XML Dom object
                XmlDocument xdWaterMeters = new XmlDocument();
                /* Get the file that holds a list of water meters
                 * and assign that file to a string variable. */
                string? strWaterMeters = @"C:\Stellar Water Point\WaterMeters.xml";
    
                /* If the user provided a meter number and clicked the Find button,
                 * check whether a file for water meters was previously created. */
                if (!File.Exists(strWaterMeters))
                {
                    // If a file for water meters was not created already, display a message box...
                    MessageBox.Show("There is no file for the water meters in the system.",
                                    "Stellar Water Point",
                                    MessageBoxButtons.OK, MessageBoxIcon.Information);
                    // .. and stop the operation.
                    return;
                }
    
                /* Since a file of water meters exists, open it.
                 * Store the list of water meters in the XML Dom object that was previously created. */
                xdWaterMeters.Load(strWaterMeters);
    
                /* From the list of XML elements, get a list of elements based one named meter-number. */
                XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.GetElementsByTagName("meter-number");
    
                // Visit each XML node from the list
                foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                {
                    /* When you get to an element, check whether its meter number is 
                     * the same number the user had typed. */
                    if (xnWaterMeter.InnerText == mtbMeterNumber.Text)
                    {
                        /* If you find that meter number, enquire from 
                         * the user if the water meter must be deleted. 
                         * To get that information, display a message box with a Yes and a No buttons. */
                        if (MessageBox.Show("Are you sure you want to delete this water meter record from the system?",
                                        "Stellar Water Point",
                                        MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                        {
                            // If the user had clicked Yes, delete the water meter.
                            xdWaterMeters.DocumentElement.RemoveChild(xnWaterMeter.ParentNode!);
                            break;
                        }
                    }
                }
    
                // Since the list of water meters has been changed, save its new version
                xdWaterMeters.Save(strWaterMeters);
    
                /* After the deletion operation, close the dialog box and
                 * return to the Central form of water meters. */
                Close();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  13. In the Solution Explorer, below the WaterMeters folder, double-click Central.cs
  14. From the Toolbox, add two buttons to the form below the list view and on the right side of the Edit Water Meter button
  15. Change the characteristics of the new buttons as follows:

    Stellar Water Point - Water Meters

    Control (Name) Other Properties
    ListView List View lvwWaterMeters FullRowSelect: True
    GridLines: True
    View: Details
    Anchor: Top, Bottom, Left, Right
    Button Button btnDeleteWateMeter &Delete Water Meter...
    Anchor: Bottom, Right
    Button Button btnClose &Close
    Anchor: Bottom, Right
  16. In the Solution Explorer, below WaterMeters, double-click Central.cs to open its form
  17. Double-click the Delete Water Meter button
  18. Return to the Central form of the water meters and double-click the Close button
  19. Change the document as follows:
    using System.Xml;
    
    namespace StellarWaterPoint10.WaterMeters
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowWaterMeters()
            {
                // Create an XML Dom reference
                XmlDocument xdWaterMeters = new XmlDocument();
                // Declare a string variable to have the file that holds a list of water meters
                string? strWaterMeters = @"C:\Stellar Water Point\WaterMeters.xml";
    
                // Create a FileInfo object that holds a reference to the file of water meters
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                // If you are about to display a list of water meters, first empty the list view
                lvwWaterMeters.Items.Clear();
    
                // Check whether a file for water meters was previously created.
                if (fiWaterMeters.Exists)
                {
                    // If such a file exists, create a Stream for it
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        // Store the stream of water meters into the XML Dom that was created earlier
                        xdWaterMeters.Load(fsWaterMeters);
                        // Get a list of the water meter elements from the XML Dom object
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.ChildNodes;
    
                        int i = 1;
    
                        // Check each water meter
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            // Create a list view item to hold a record of a water meter
                            ListViewItem lviWaterMeter = new ListViewItem(i.ToString());
    
                            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);
    
                            // Pass the list view item to the list view object on the form
                            lvwWaterMeters.Items.Add(lviWaterMeter);
    
                            i++;
                        }
                    }
                }
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                // When the open opens, make an attempt to display a list of water meters.
                ShowWaterMeters();
            }
    
            private void btnNewWaterMeter_Click(object sender, EventArgs e)
            {
                // Get a reference to the form used to add a water meter
                Create wm = new();
                // Create a FileInfo object
                FileInfo? fiWaterMeters = null;
                // Create a file stream object
                FileStream? fsWaterMeters = null;
                // Create an XML Dom object
                XmlDocument xdWaterMeters = new XmlDocument();
                // Declare a string for a file to hold a list of water meters
                string? strWaterMeters = @"C:\Stellar Water Point\WaterMeters.xml";
    
                /* Display the form used to create a water meter. 
                 * If the user finishes using that form and click the OK button... */
                if (wm.ShowDialog() == DialogResult.OK)
                {
                    // Store the file of water meters into the FileInfo object that was previously created.
                    fiWaterMeters = new FileInfo(strWaterMeters);
    
                    /* Find out whether a list of water meters was previously created 
                     * and was stored in the string file declared above. */
                    if (fiWaterMeters.Exists)
                    {
                        /* If that file exists already, create a Stream object 
                         * for it with a read-only status. */
                        using (fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open,
                                                              FileAccess.Read, FileShare.Read))
                        {
                            // Pass the list of water meters to the XML Dom object created earlier
                            xdWaterMeters.Load(fsWaterMeters);
                        }
                    }
                    else
                    {
                        // If a file for water meters was not previously created, create it now...
                        using (fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Create,
                                                              FileAccess.Write, FileShare.Write))
                        {
                            // and create the root XML element for it
                            xdWaterMeters.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                                                  "<water-meters></water-meters>");
                            // Make sure you save the new file
                            xdWaterMeters.Save(fsWaterMeters);
                        }
                    }
    
                    // Now that the file exists, open it
                    using (fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.OpenOrCreate,
                                                          FileAccess.ReadWrite, FileShare.ReadWrite))
                    {
                        // Start creating a new Water Meter XML element
                        XmlElement xeWaterMeter = xdWaterMeters.CreateElement("water-meter");
    
                        /* Use the values that the user had typed in the Create form.
                         * Use those values to create the child elements of the new water meter node.
                         * Assign the combination of child elements to the new water meter node. */
                        xeWaterMeter.InnerXml = "<meter-number>" + wm.mtbMeterNumber.Text + "</meter-number>" +
                                                "<make>" + wm.txtMake.Text + "</make>" +
                                                "<model>" + wm.txtModel.Text + "</model>" +
                                                "<meter-size>" + wm.txtMeterSize.Text + "</meter-size>";
                        // Once the XML element is ready, add/append it to the XML Dom that was previously created.
                        xdWaterMeters.DocumentElement!.AppendChild(xeWaterMeter);
                        // Once the new element has been created and add it to the file, save that file
                        xdWaterMeters.Save(fsWaterMeters);
                    }
                }
    
                /* Whenever the user has finished using the Create form, 
                 * make an attempt to display the list of water meters. */
                ShowWaterMeters();
            }
    
            private void btnViewWaterMeter_Click(object sender, EventArgs e)
            {
                /* Get a reference to the dialog box that is used 
                 * to view information about a water meter. */
                Details view = new();
                // Display that dialog box
                view.ShowDialog();
    
                // After using the dialog box, make an attempt to display the list of water meters.
                ShowWaterMeters();
            }
    
            private void btnEditWaterMeter_Click(object sender, EventArgs e)
            {
                /* Get a reference to the dialog box that is used 
                 * to update the details of a water meter. */
                Editor editor = new();
                // Display that dialog box
                editor.ShowDialog();
    
                // After using the dialog box, make an attempt to display the list of water meters.
                ShowWaterMeters();
            }
    
            private void btnDeleteWateMeter_Click(object sender, EventArgs e)
            {
                Delete del = new Delete();
                del.ShowDialog();
    
                ShowWaterMeters();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  20. To execute the application, on the main menu, click Debug -> Start Without Debugging:

    Stellar Water Point - Water Meters

  21. On the Central form, click the Water Meters button:

    Stellar Water Point - Water Meters

  22. On the Central form of the water meters, click the Delete Water Meter button:

    Stellar Water Point - Water Meter Deletion

  23. In the Meter # text, type 588-279-663
  24. Click the Find button:

    Stellar Water Point - Water Meter Deletion

  25. Click the Delete button:

    Stellar Water Point - Water Meter Deletion

  26. Read the text on the message box:

    Stellar Water Point - Water Meter Deletion

    On the message box, click Yes

    Stellar Water Point - Water Meters

  27. Close the forms and return to your programming environment
  28. From the Windows Explorer, open the WaterMeters.xml file
  29. Replace the content of the file with the provided file
  30. Save the file
  31. Return to your programming environment

Customers

Introduction

Obviously, customers are the ones who use the services of the bussiness whose application we are building. Obviously, a customer is represented by a business account, and a water meter must be associated to a customer's account. As seen with water meterrs, the application will use forms to create and manage customers accounts.

Customers Accounts

Our application will wuse a database that contains a list of customers. As seen with water meter records, we assume that some time to time, a user will want to view those records. To display a list of customers, we will create a form equipped with a list view.

Practical LearningPractical Learning: Displaying Customers Accounts

  1. To create a folder, in the Solution Explorer, right-click the StellarWaterPoint1 project -> Add -> New Folder
  2. Type Customers as the name of the folder
  3. To create a form, in the Solution Explorer, right-click Customers -> Add -> Form (Windows Forms)...
  4. Type Central
  5. Click Add
  6. In the Toolbox, click the ListView button and click the form
  7. In the Properties window, change the characteristics of the list view as follows:
    Control (Name) Other Properties
    ListView List View lvwCustomers FullRowSelect: True
    GridLines: True
    View: Details
    Anchor: Top, Bottom, Left, Right
  8. On the form, right-click the list view and click Edit Columns...
  9. Create the columns as follows:

    Stellar Water Point - Customers

    (Name) Text TextAlign Width
    colCustomerId Id   40
    colAccountNumber Account # Center 150
    colAccountName Account Name   200
    colMeterNumber Meter # Center 100
    colAccountType Account Type   200
    colAddress Address   250
    colCity City   125
    colCounty County   125
    colState State Center  
    colZIPCode ZIP-Code Center 125
  10. Click OK
  11. Doubte-click an unoccupied area of the form to generate its Load event
  12. Change the document as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.Customers
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowCustomers()
            {
                int i = 1;
    
                lvwCustomers.Items.Clear();
    
                XmlDocument xdCustomers = new XmlDocument();
                string? strCustomers = @"C:\Stellar Water Point\Customers.xml";
    
                FileInfo? fiCustomers = new FileInfo(strCustomers);
    
                if (fiCustomers.Exists)
                {
                    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)
                        {
                            ListViewItem lviCustomer = new ListViewItem(i.ToString());
    
                            lviCustomer.SubItems.Add(xnCustomer.FirstChild!.InnerText);   // Account #
                            lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling!.InnerText);   // Account Name
                            lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling.NextSibling!.InnerText); // Meter #
                            lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling.NextSibling.NextSibling!.InnerText);   // Account Type
                            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 Central_Load(object sender, EventArgs e)
            {
                ShowCustomers();
            }       
        }
    }
  13. In the Solution Explorer, double-click WaterDistribution.cs to diaply the primary form of the application
  14. From the Toolbox, add a button to the form
  15. From the Properties window, change the characteristics of the button as follows:

    Stellar Water Point

    Control (Name) Text Font
    Button Button btnCustomers &Customers... Times New Roman, 24pt, style=Bold
  16. On the form, double-click the Customers button
  17. Implement the event as follows:
    namespace StellarWaterPoint3
    {
        public partial class WaterDistribution : Form
        {
            public WaterDistribution()
            {
                InitializeComponent();
            }
    
            private void WaterDistribution_Load(object sender, EventArgs e)
            {
                // If the directory for the database doesn't yet exist, create it
                Directory.CreateDirectory(@"C:\Stellar Water Point");
            }
    
            private void btnCustomers_Click(object sender, EventArgs e)
            {
                Customers.Central central = new Customers.Central();
    
                central.ShowDialog();
            }
    
            private void btnWaterMeters_Click(object sender, EventArgs e)
            {
                WaterMeters.Central central = new WaterMeters.Central();
    
                central.ShowDialog();
            }
        }
    }

A Customer's Account

As mentioned already, our application will use a database that contains a list of customers. This means that a customer must have an account. We will create a form to let the user create an account. One important detail is that a customer must have a water meter. Therefore, each customer account must have an associated water meter. To set this up, on the form used to create a customer's account, we will add a text box that allows a user to specify and validate a water meter.

Practical LearningPractical Learning: Creating a Customer Account

  1. In the Solution Explorer, right-click the Customers folder -> Add -> Form (Windows Forms)...
  2. Type Create as the name of the file
  3. Click Add
  4. Design the form as follows:

    Stellar Water Point - New Customer Account

    Control (Name) Text Other Properties
    Label Label   &Account #:  
    MaskedTextBox Masked Text Box mtbAccountNumber   Masked: 0000-000-0000
    Label Label   &Account Name:  
    TextBox Text Box txtAccountName    
    Label Label   &Meter #:  
    MaskedTextBox Masked Text Box mtbMeterNumber   Masked: 000-000-000
    Button Button btnFindWaterMeter &Find Water Meter  
    Label Label   Meter &Details:  
    TextBox Text Box txtMeterDetails   Enabled: False
    Label Label   &Account Type:  
    ComboBox Combo Box cbxAccountsTypes   Items:
    OTH - Other
    BUS - General Business
    RES - Residential Household
    SGO - Social/Government/Non - Profit Organization
    UUO - Unidentified or Unclassified Type of Organization
    WAT - Water Intensive Business(Laudromat, Hair Salon, Restaurant, etc
    Label Label   &Address:  
    TextBox Text Box txtAddress    
    Label Label   C&ity:  
    TextBox Text Box txtCity    
    Label Label   C&ounty:  
    TextBox Text Box txtCounty    
    Label Label   &State:  
    TextBox Text Box txtState    
    Label Label   &ZIP-Code:  
    MaskedTextBox Masked Text Box mtbZIPCode   Masked: Zip-Code
    Button Button btnSaveCustomerAccount S&ave Customer Account DialogResult: OK
    Button Button btnClose &Close DialogResult: Cancel
  5. Using the Properties window, change some characteristics of the form as follows:
    FormBorderStyle: FixedDialog
    Text:            Stellar Water Point - Customer Account Setup
    StartPosition:   CenterScreen
    AcceptButton:    btnSaveCustomerAccount
    CancelButton:    btnClose
    MinimizeBox:     False
    MaximizeBox:     False
  6. On the form, double-click the Find Water Meter button
  7. Change the document as follows:
    using System.Xml;
    
    namespace StellarWaterPoint1.Customers
    {
        public partial class Create : Form
        {
            public Create()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterMeter_Click(object sender, EventArgs e)
            {
                // Create an XML Dom object
                XmlDocument xdWaterMeters = new XmlDocument();
                // Declare a string variable and assign the file of water meters to it
                string? strWaterMeters = @"C:\Stellar Water Point\WaterMeters.xml";
                // Create a FileInfo object to manage the file that has the water meters
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                // Find out whether a file for water meters exists already
                if (fiWaterMeters.Exists)
                {
                    // If a file for water meters exists already, create a Stream object for it
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open,
                                                                      FileAccess.Read, FileShare.Read))
                    {
                        /* From the file of water meters, store the list of water meters 
                         * in the XML Dom that was previously created. */
                        xdWaterMeters.Load(fsWaterMeters);
    
                        /* Check the list of water meters. 
                         * Find a water meter that has the same name as the meter number that the user typed. */
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + mtbMeterNumber.Text + "']")!;
    
                        // If such a water meter exists...
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            // ... store its details in the meter details text box.
                            txtMeterDetails.Text = xnWaterMeter.NextSibling!.InnerText + " " +
                                                   xnWaterMeter.NextSibling.NextSibling!.InnerText + " (Meter Size: " +
                                                   xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText + ")";
                        }
                    }
                }
            }
        }
    }
  8. In the Solution Explorer, below the Customers folder, double-click Central.cs
  9. From the Toolbox, add a button to the form below the list view
  10. Change the characteristics of the button as follows:

    Stellar Water Point - Water Meters

    Control (Name) Other Properties
    ListView List View lvwCustomers  
    Button Button btnCreateCustomerAccount &Create Customer Account...
    Anchor: Bottom, Right
  11. Double-click the Create Customer Account button
  12. Change the document as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.Customers
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowCustomers()
            {
                int i = 1;
    
                lvwCustomers.Items.Clear();
    
                XmlDocument xdCustomers = new XmlDocument();
                string? strCustomers = @"C:\Stellar Water Point\Customers.xml";
    
                FileInfo? fiCustomers = new FileInfo(strCustomers);
    
                if (fiCustomers.Exists)
                {
                    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)
                        {
                            ListViewItem lviCustomer = new ListViewItem(i.ToString());
    
                            lviCustomer.SubItems.Add(xnCustomer.FirstChild!.InnerText);   // Account #
                            lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling!.InnerText);   // Account Name
                            lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling.NextSibling!.InnerText); // Meter #
                            lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling.NextSibling.NextSibling!.InnerText);   // Account Type
                            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 Central_Load(object sender, EventArgs e)
            {
                // When the form opens, try displaying the list of customers
                ShowCustomers();
            }
    
            private void btnCreateCustomerAccount_Click(object sender, EventArgs e)
            {
                Create create = new Create();
    
                if (create.ShowDialog() == DialogResult.OK)
                {
                    /* Make sure the user provides an account number for the new account. 
                     * If not, don't create the account. */
                    if (string.IsNullOrEmpty(create.mtbAccountNumber.Text))
                    {
                        MessageBox.Show("You must provide an account number for the new customer. " +
                                        "Otherwise, the account cannot be created.",
                                        "Stellar Water Point",
                                        MessageBoxButtons.OK, MessageBoxIcon.Information);
    
                        return;
                    }
    
                    /* If the meter details text box is empty, it means the user didn't enter
                     * a meter number, in which case there is no water meter associated 
                     * with the account. The account cannot be created. */
                    if (string.IsNullOrEmpty(create.txtMeterDetails.Text))
                    {
                        MessageBox.Show("You must enter a water meter to associate with a new customer's account.",
                                        "Stellar Water Point",
                                        MessageBoxButtons.OK, MessageBoxIcon.Information);
                        
                        return;
                    }
                    
                    // Create a FileInfo object that will be used to manage a file
                    FileInfo? fiCustomers = null;
                    // Start a Stream object that will be used to manage a file
                    FileStream? fsCustomers = null;
                    // Create an XML Dom
                    XmlDocument xdCustomers = new XmlDocument();
                    // Declare a string variable for the file that contains a list of customers
                    string? strCustomers = @"C:\Stellar Water Point\Customers.xml";
                    
                    // Pass the file of customers to the FileInfo object that was started
                    fiCustomers = new FileInfo(strCustomers);
    
                    // Find out whether that file was already created
                    if (fiCustomers.Exists)
                    {
                        /* If that file was already created, open it through 
                         * the Stream object that was previously initiated. */
                        using (fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open,
                                                            FileAccess.Read, FileShare.Read))
                        {
                            // Pass the Stream object to the XML Dom that was previously created.
                            xdCustomers.Load(fsCustomers);
                        }
                    }
                    else
                    {
                        /* If the file of customers was not created already, start by 
                         * initializing the Stream object that was previously initiated. */
                        using (fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Create, FileAccess.Write, FileShare.Write))
                        {
                            // Create a root to start the XML file
                            xdCustomers.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                                                "<customers></customers>");
                            // Once the file has been started, save it
                            xdCustomers.Save(fsCustomers);
                        }
                    }
    
                    // Now that we have an XML file for customers, open it
                    using (fsCustomers = new FileStream(fiCustomers.FullName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
                    {
                        /* We want to create an XML element to be added to the XML file.
                         * To start, create an XML element named "customer". */
                        XmlElement xeCustomer = xdCustomers.CreateElement("customer");
    
                        // Create/Format the child nodes of the "customer" element
                        xeCustomer.InnerXml = "<account-number>" + create.mtbAccountNumber.Text + "</account-number>" +
                                              "<account-name>"   + create.txtAccountName.Text   + "</account-name>"   +
                                              "<meter-number>"   + create.mtbMeterNumber.Text   + "</meter-number>"   +
                                              "<account-type>"   + create.cbxAccountsTypes.Text + "</account-type>"   +
                                              "<address>"        + create.txtAddress.Text       + "</address>"        +
                                              "<city>"           + create.txtCity.Text          + "</city>"           +
                                              "<county>"         + create.txtCounty.Text        + "</county>"         +
                                              "<state>"          + create.txtState.Text         + "</state>"          +
                                              "<zip-code>"       + create.mtbZIPCode.Text       + "</zip-code>";
                        xdCustomers.DocumentElement!.AppendChild(xeCustomer);
                        xdCustomers.Save(fsCustomers);
                    }
                }
    
                ShowCustomers();
            }
        }
    }
  13. To execute the application, on the main menu, click Debug -> Start Without Debugging:

    Stellar Water Point - New Customer Account

  14. On the Water Distribution form, click the Customers button:

    Stellar Water Point - Customers Accounts

  15. On the Central form of the customers, click the Create Customer Account button:

    Stellar Water Point - Customers Accounts

  16. In the account # text box, type 9279-570-8394
  17. In the meter # text box, type 799-528-461
  18. Click the Find water meter button
  19. Enter the other values as follows:
    Account #:    9279-570-8394
    Account Name: Thomas Stones
    Meter #:      799-528-461
    Account Type: RES - Residential Household
    Address:      10252 Broward Ave #D4
    City:         Frederick
    County:       Frederick
    State:        MD
    ZIP-Code:     21703-4422

    Stellar Water Point - New Customer Account

  20. Click Save Customer Account
  21. In the same way, create the following two records:
    Account # Account Name Meter # Account Type Address City County State ZIP-Code
    4086-938-4783 Hernola Dough 594-827-359 UUO - Unidentified or Unclassified Type of Organization 10 10 Hexagonal Drv Winston Yoke Penn 11402-4411
    7080-583-5947 Sunny Yard 827-508-248 WAT - Water Intensive Business(Laudromat, Hair Salon, Restaurant, etc 663 Sherry Wood East Street Shimpstown Franklin PA 17236-2626

    Stellar Water Point - Customers

  22. Close the forms and return to your programming environment

A Review of a Customer's Account

.

Practical LearningPractical Learning: Creating a Water Meter Record

  1. To create a form, in the Solution Explorer, right-click Customers -> Add -> Form (Windows Forms)...
  2. For the Name of the form, type Details
  3. Press Enter
  4. Design the form as follows:

    Stellar Water Point - New Customer Account

    Control (Name) Text Other Properties
    Label Label   &Account #:  
    MaskedTextBox Masked Text Box mtbAccountNumber   Masked: 0000-000-0000
    Button Button btnFindCustomerAccount &Find Customer Account  
    Label Label   Account Name:  
    TextBox Text Box txtAccountName   Enabled: False
    Label Label   Meter #:  
    TextBox Masked Text Box txtMeterNumber   Enabled: False
    Label Label   Meter Details:  
    TextBox Text Box txtMeterDetails   Enabled: False
    Label Label   Account Type:  
    TextBox Text Box txtAccountType   Enabled: False
    Label Label   Address:  
    TextBox Text Box txtAddress   Enabled: False
    Label Label   City:  
    TextBox Text Box txtCity   Enabled: False
    Label Label   County:  
    TextBox Text Box txtCounty   Enabled: False
    Label Label   State:  
    TextBox Text Box txtState   Enabled: False
    Label Label   ZIP-Code: Enabled: False
    TextBox Masked Text Box txtZIPCode   Enabled: False
    Button Button btnClose &Close
  5. Using the Properties window, change some characteristics of the form as follows:
    FormBorderStyle: FixedDialog
    Text:            Stellar Water Point - Customer Account Setup
    StartPosition:   CenterScreen
    MinimizeBox:     False
    MaximizeBox:     False
  6. On the form, double-click the Find Cust&omer Account button
  7. Implement the event as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.Customers
    {
        public partial class Details : Form
        {
            public Details()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                XmlDocument xdCustomers = new XmlDocument();
                string? strCustomers = @"C:\Stellar Water Point\Customers.xml";
    
                FileInfo? fiCustomers = new FileInfo(strCustomers);
    
                string strMeterNumber = string.Empty;
    
                if (fiCustomers.Exists)
                {
                    using (FileStream? fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdCustomers.Load(fsCustomers);
                        XmlNodeList xnlCustomers = xdCustomers.DocumentElement!.SelectNodes("//account-number[.='" + mtbAccountNumber.Text + "']")!;
    
                        foreach (XmlNode xnCustomer in xnlCustomers)
                        {
                            //mtbAccountNumber.Text = xnCustomer.NextSibling!.InnerText;   // Meter #
                            txtAccountName.Text   = xnCustomer.NextSibling!.InnerText; // Account Name
                            txtMeterNumber.Text   = xnCustomer.NextSibling.NextSibling!.InnerText;   // Meter Number
                            strMeterNumber        = xnCustomer.NextSibling.NextSibling!.InnerText;   // Meter Number
                            txtAccountType.Text   = xnCustomer.NextSibling.NextSibling.NextSibling!.InnerText;   // Account Type
                            txtAddress.Text       = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText;   // Address
                            txtCity.Text          = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText;   // City
                            txtCounty.Text        = xnCustomer.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.InnerText;   // County
                            txtState.Text         = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;   // State
                            txtZIPCode.Text       = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText; // ZIP-Code
                        }
                    }
                }
    
                XmlDocument xdWaterMeters = new XmlDocument();
                string? strWaterMeters = @"C:\Stellar Water Point6\WaterMeters.xml";
    
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                if (fiWaterMeters.Exists)
                {
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdWaterMeters.Load(fsWaterMeters);
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + strMeterNumber + "']")!;
    
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            txtMeterDetails.Text = xnWaterMeter.NextSibling!.InnerText + " " +
                                                   xnWaterMeter.NextSibling.NextSibling!.InnerText + " (Meter Size: " +
                                                   xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText + ")";
                        }
                    }
                }
            }
        }
    }
  8. Return to the form and double-click the Close button
  9. Implement the event as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.Customers
    {
        public partial class Details : Form
        {
            public Details()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                // Create an XML DOM object for the customers records
                XmlDocument xdCustomers = new XmlDocument();
                // Declare a variable for a file that holds the list of customers
                string? strCustomers = @"C:\Stellar Water Point6\Customers.xml";
    
                // Create a FileInfo object for the customers
                FileInfo? fiCustomers = new FileInfo(strCustomers);
    
                // We will need to know the water meter associated with this customer account
                string strMeterNumber = string.Empty;
    
                // Check whether the file that holds a list of customers exists
                if (fiCustomers.Exists)
                {
                    // If that exists, open it and pass it to a FileStream object
                    using (FileStream? fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        // Get the list of customers and pass the records to the XML DOM object created earlier
                        xdCustomers.Load(fsCustomers);
                        // Create an XmlNodeList list of customers using XPath
                        XmlNodeList xnlCustomers = xdCustomers.DocumentElement!.SelectNodes("//account-number[.='" + mtbAccountNumber.Text + "']")!;
    
                        // Check each node of the XML record and display its values in each Windows control on the form
                        foreach (XmlNode xnCustomer in xnlCustomers)
                        {
                            //mtbAccountNumber.Text = xnCustomer.NextSibling!.InnerText;   // Meter #
                            txtAccountName.Text = xnCustomer.NextSibling!.InnerText; // Account Name
                            txtMeterNumber.Text = xnCustomer.NextSibling.NextSibling!.InnerText;   // Meter Number
                            strMeterNumber = xnCustomer.NextSibling.NextSibling!.InnerText;   // Meter Number
                            txtAccountType.Text = xnCustomer.NextSibling.NextSibling.NextSibling!.InnerText;   // Account Type
                            txtAddress.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText;   // Address
                            txtCity.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText;   // City
                            txtCounty.Text = xnCustomer.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.InnerText;   // County
                            txtState.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;   // State
                            txtZIPCode.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText; // ZIP-Code
                        }
                    }
                }
    
                // Create an XML DOM object for the water meters records
                XmlDocument xdWaterMeters = new XmlDocument();
                // Declare a variable for a file that holds the list of water meters
                string? strWaterMeters = @"C:\Stellar Water Point6\WaterMeters.xml";
    
                // Create a FileInfo object for the customers
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                // Check whether the file that holds a list of water meters exists
                if (fiWaterMeters.Exists)
                {
                    // Get the list of water meters and pass the records to the XML DOM object
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        // Get the list of water meters and pass the records to the XML DOM object
                        xdWaterMeters.Load(fsWaterMeters);
                        // Create an XmlNodeList list of water meters using XPath
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + strMeterNumber + "']")!;
    
                        // Check each node of the XML record
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            /* Get the values for the water meter.
                             * Create a sentence and display it in the Meter Details text box. */
                            txtMeterDetails.Text = xnWaterMeter.NextSibling!.InnerText + " " +
                                                   xnWaterMeter.NextSibling.NextSibling!.InnerText + " (Meter Size: " +
                                                   xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText + ")";
                        }
                    }
                }
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  10. In the Solution Explorer, below the Customers folder, double-click Central.cs to open its form
  11. From the Toolbox, add a button to the form below the list view and to the right of the Create Customer Account button
  12. Change the characteristics of the button as follows:

    Stellar Water Point - Water Meters

    Control (Name) Other Properties
    Button Button btnViewCustomerAccount &View Customer Account...
    Anchor: Bottom, Right
  13. Double-click the View Customer Account button
  14. Change the document as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.Customers
    {
        public partial class Details : Form
        {
            public Details()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                XmlDocument xdCustomers = new XmlDocument();
                string? strCustomers = @"C:\Stellar Water Point6\Customers.xml";
    
                FileInfo? fiCustomers = new FileInfo(strCustomers);
    
                string strMeterNumber = string.Empty;
    
                if (fiCustomers.Exists)
                {
                    using (FileStream? fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdCustomers.Load(fsCustomers);
                        XmlNodeList xnlCustomers = xdCustomers.DocumentElement!.SelectNodes("//account-number[.='" + mtbAccountNumber.Text + "']")!;
    
                        foreach (XmlNode xnCustomer in xnlCustomers)
                        {
                            //mtbAccountNumber.Text = xnCustomer.NextSibling!.InnerText; // Meter #
                            txtAccountName.Text     = xnCustomer.NextSibling!.InnerText; // Account Name
                            txtMeterNumber.Text     = xnCustomer.NextSibling.NextSibling!.InnerText;   // Meter Number
                            strMeterNumber          = xnCustomer.NextSibling.NextSibling!.InnerText;   // Meter Number
                            txtAccountType.Text     = xnCustomer.NextSibling.NextSibling.NextSibling!.InnerText;   // Account Type
                            txtAddress.Text         = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText;   // Address
                            txtCity.Text            = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText;   // City
                            txtCounty.Text          = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.InnerText;   // County
                            txtState.Text           = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;   // State
                            txtZIPCode.Text         = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText; // ZIP-Code
                        }
                    }
                }
    
                XmlDocument xdWaterMeters = new XmlDocument();
                string? strWaterMeters = @"C:\Stellar Water Point6\WaterMeters.xml";
    
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                if (fiWaterMeters.Exists)
                {
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdWaterMeters.Load(fsWaterMeters);
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + strMeterNumber + "']")!;
    
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            txtMeterDetails.Text = xnWaterMeter.NextSibling!.InnerText + " " +
                                                   xnWaterMeter.NextSibling.NextSibling!.InnerText + " (Meter Size: " +
                                                   xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText + ")";
                        }
                    }
                }
            }
        }
    }
  15. To execute the application, on the main menu, click Debug -> Start Without Debugging

    Stellar Water Point

  16. On the Water Distribution form, click the Customers button:

    Stellar Water Point - Customers

  17. On the Central form of customers, click the View Customer Account button:

    Stellar Water Point - View Water Meter

  18. In the Account # text box, type 4086-938-4783
  19. Click the Find Customer Account button:

    Stellar Water Point - View Water Meter

  20. Close the Details form
  21. Close the forms and return to your programming environment

Updating a Customer's Account

.

Practical LearningPractical Learning: Updating a Water Meter

  1. To create a form, in the Solution Explorer, right-click WaterMeters -> Add -> Form (Windows Forms)...
  2. For the Name of the file, type Editor as the name of the form
  3. Click Add
  4. Resize the Editor form to have the same size as the Create form of the Customers section
  5. Copy everything from the Create form of the Customers section and paste it in the Editor form of the Customers section
  6. Delete the bottom two buttons on the form
  7. Change the design of the form as follows:

    Stellar Water Point - New Customer Account

    Control (Name) Text Other Properties
    Button Button btnFindCustomerAccount &Find Customer Account  
    Button Button btnUpdateWateMeter &Update Water Meter DialogResult: OK
    Button Button btnClose &Close DialogResult: Cancel
  8. Using the Properties window, change some characteristics of the form as follows:
    FormBorderStyle: FixedDialog
    Text:            Stellar Water Point - Customer Account Editor
    StartPosition:   CenterScreen
    AcceptButton:    btnUpdateWateMeter
    CancelButton:    btnClose
    MinimizeBox:     False
    MaximizeBox:     False
  9. On the form, double-click the Find Customer Account button
  10. Change the document as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.Customers
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                XmlDocument xdCustomers = new XmlDocument();
                string? strCustomers = @"C:\Stellar Water Point6\Customers.xml";
    
                FileInfo? fiCustomers = new FileInfo(strCustomers);
    
                string strMeterNumber = string.Empty;
    
                if (fiCustomers.Exists)
                {
                    using (FileStream? fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdCustomers.Load(fsCustomers);
                        XmlNodeList xnlCustomers = xdCustomers.DocumentElement!.SelectNodes("//account-number[.='" + mtbAccountNumber.Text + "']")!;
    
                        foreach (XmlNode xnCustomer in xnlCustomers)
                        {
                            //mtbAccountNumber.Text = xnCustomer.NextSibling!.InnerText;   // Meter #
                            txtAccountName.Text   = xnCustomer.NextSibling!.InnerText; // Account Name
                            mtbMeterNumber.Text   = xnCustomer.NextSibling.NextSibling!.InnerText;   // Meter Number
                            strMeterNumber        = xnCustomer.NextSibling.NextSibling!.InnerText;   // Meter Number
                            cbxAccountsTypes.Text = xnCustomer.NextSibling.NextSibling.NextSibling!.InnerText;   // Account Type
                            txtAddress.Text       = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText;   // Address
                            txtCity.Text          = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText;   // City
                            txtCounty.Text        = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.InnerText;   // County
                            txtState.Text         = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;   // State
                            mtbZIPCode.Text       = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText; // ZIP-Code
                        }
                    }
                }
    
                XmlDocument xdWaterMeters = new XmlDocument();
                string? strWaterMeters = @"C:\Stellar Water Point6\WaterMeters.xml";
    
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                if (fiWaterMeters.Exists)
                {
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdWaterMeters.Load(fsWaterMeters);
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + strMeterNumber + "']")!;
    
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            txtMeterDetails.Text = xnWaterMeter.NextSibling!.InnerText + " " +
                                                   xnWaterMeter.NextSibling.NextSibling!.InnerText + " (Meter Size: " +
                                                   xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText + ")";
                        }
                    }
                }
            }
        }
    }
  11. Return to the form and double-click the Find Water Meter button
  12. Implement the event as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.Customers
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                XmlDocument xdCustomers = new XmlDocument();
                string? strCustomers = @"C:\Stellar Water Point6\Customers.xml";
    
                FileInfo? fiCustomers = new FileInfo(strCustomers);
    
                string strMeterNumber = string.Empty;
    
                if (fiCustomers.Exists)
                {
                    using (FileStream? fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdCustomers.Load(fsCustomers);
                        XmlNodeList xnlCustomers = xdCustomers.DocumentElement!.SelectNodes("//account-number[.='" + mtbAccountNumber.Text + "']")!;
    
                        foreach (XmlNode xnCustomer in xnlCustomers)
                        {
                            //mtbAccountNumber.Text = xnCustomer.NextSibling!.InnerText;
                            txtAccountName.Text   = xnCustomer.NextSibling!.InnerText;
                            mtbMeterNumber.Text   = xnCustomer.NextSibling.NextSibling!.InnerText;
                            strMeterNumber        = xnCustomer.NextSibling.NextSibling!.InnerText;
                            cbxAccountsTypes.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;
                            mtbZIPCode.Text       = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                        }
                    }
                }
    
                XmlDocument xdWaterMeters = new XmlDocument();
                string? strWaterMeters = @"C:\Stellar Water Point6\WaterMeters.xml";
    
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                if (fiWaterMeters.Exists)
                {
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdWaterMeters.Load(fsWaterMeters);
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + strMeterNumber + "']")!;
    
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            txtMeterDetails.Text = xnWaterMeter.NextSibling!.InnerText + " " +
                                                   xnWaterMeter.NextSibling.NextSibling!.InnerText + " (Meter Size: " +
                                                   xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText + ")";
                        }
                    }
                }
            }
    
            private void btnFindWateMeter_Click(object sender, EventArgs e)
            {
                XmlDocument xdWaterMeters = new XmlDocument();
                string? strWaterMeters = @"C:\Stellar Water Point6\WaterMeters.xml";
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                if (fiWaterMeters.Exists)
                {
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open,
                                                                      FileAccess.Read, FileShare.Read))
                    {
                        xdWaterMeters.Load(fsWaterMeters);
    
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + mtbMeterNumber.Text + "']")!;
    
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            txtMeterDetails.Text = xnWaterMeter.NextSibling!.InnerText + " " +
                                                   xnWaterMeter.NextSibling.NextSibling!.InnerText + " (Meter Size: " +
                                                   xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText + ")";
                        }
                    }
                }
            }
        }
    }
  13. In the Solution Explorer, below the Customers folder, double-click Central.cs
  14. From the Toolbox, add a button to the form below the list view and on the right side of the View Customer Account button
  15. Change the characteristics of the button as follows:

    Stellar Water Point - Water Meters

    Control (Name) Text Other Properties
    ListView List View lvwCustomers   No Change
    Button Button btnNewCustomerAccount   No Change
    Button Button btnViewCustomerAccount   No Change
    Button Button btnEditCustomerAccount &Edit Water Meter... Anchor: Bottom, Right
  16. Display the Central form of the Customers folder
  17. Double-click the Update Water Meter button
  18. Implement the event as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.Customers
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowCustomers()
            {
                . . .
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                ShowCustomers();
            }
    
            private void btnCreateCustomerAccount_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void ViewCustomerAccount_Click(object sender, EventArgs e)
            {
                Details det = new Details();
    
                det.ShowDialog();
            }
    
            private void btnEditCustomerAccount_Click(object sender, EventArgs e)
            {
                Editor editor = new();
                XmlDocument xdCustomers = new XmlDocument();
                string? strCustomers = @"C:\Stellar Water Point6\Customers.xml";
    
                if (editor.ShowDialog() == DialogResult.OK)
                {
                    xdCustomers.Load(strCustomers);
    
                    XmlNodeList xnlCustomers = xdCustomers.DocumentElement!.GetElementsByTagName("account-number");
    
                    foreach (XmlNode xnCustomer in xnlCustomers)
                    {
                        if (xnCustomer.InnerText.Contains(editor.mtbAccountNumber.Text))
                        {
                            xnCustomer.ParentNode!.InnerXml = "<account-number>" + editor.mtbAccountNumber.Text + "</account-number>" +
                                                  "<account-name>" + editor.txtAccountName.Text + "</account-name>" +
                                                  "<meter-number>" + editor.mtbMeterNumber.Text + "</meter-number>" +
                                                  "<account-type>" + editor.cbxAccountsTypes.Text + "</account-type>" +
                                                  "<address>" + editor.txtAddress.Text + "</address>" +
                                                  "<city>" + editor.txtCity.Text + "</city>" +
                                                  "<county>" + editor.txtCounty.Text + "</county>" +
                                                  "<state>" + editor.txtState.Text + "</state>" +
                                                  "<zip-code>" + editor.mtbZIPCode.Text + "</zip-code>";
    
                            xdCustomers.Save(strCustomers);
                            break;
                        }
                    }
                }
    
                ShowCustomers();    
            }
        }
    }
  19. To execute the application, on the main menu, click Debug -> Start Without Debugging

    Stellar Water Point

  20. On the main form of the application, click the Customers button:

    Stellar Water Point - Customers

  21. Click the Edit Customer Account button:

    Stellar Water Point - Water Meter Editor

  22. In the Account # text, type 4086-938-4783
  23. Click the Find Customer Account button

    Stellar Water Point - Water Meter Editor

  24. Change the values as follows:
    Account Name: Bernotte's Doughnuts
    Meter #:      580-742-825 and click Find Water Meter
    Account Type: BUS	- General Business
    Address:      10103 Hexagon Drive
    City:         Winterstown
    County:       York
    State:        PA
    ZIP-Code:     17402-8828

    Stellar Water Point - New Water Meter

  25. Click the Update Customer Account button:

    Stellar Water Point - Water Meters

  26. Close the forms and return to your programming environment

Deleting a Customer's Account

If a record is not necessary anymore on a database, the user may want to remove it. To assist the user with this operation, we will create a form withe necessary buttons.

Practical LearningPractical Learning: Deleting a Customer Account

  1. To create a form, in the Solution Explorer, right-click WaterMeters -> Add -> Form(Windows Forms)...
  2. In the Name text box, replace the string with Delete as the name of the form
  3. Press Enter
  4. Resize the Delete form to have the same size as the Details form
  5. Copy everything from the Details form and paste it in the Delete form
  6. Change the bottom button as follows:

    Stellar Water Point - New Water Meter

    Control (Name) Text Othe Properties
    Button Button btnDeleteCustomerAccount &Delete Water Meter DialogResult: OK
    Button Button btnClose &Close DialogResult: Cancel
  7. Using the Properties window, change some characteristics of the form as follows:
    FormBorderStyle: FixedDialog
    Text:            Stellar Water Point - Customer Account Deletion
    StartPosition:   CenterScreen
    AcceptButton:    btnDeleteCustomerAccount
    CancelButton:    btnClose
    MinimizeBox:     False
    MaximizeBox:     False
  8. On the form, double-click the Find Customer Account button
  9. Change the document as tollows:
    using System.Xml;
    
    namespace StellarWaterPoint3.Customers
    {
        public partial class Delete : Form
        {
            public Delete()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                // Create an XML DOM object for the customers records
                XmlDocument xdCustomers = new XmlDocument();
                // Declare a variable for a file that holds the list of customers
                string? strCustomers = @"C:\Stellar Water Point6\Customers.xml";
    
                // Create a FileInfo object for the customers
                FileInfo? fiCustomers = new FileInfo(strCustomers);
    
                // We will need to know the water meter associated with this customer account
                string strMeterNumber = string.Empty;
    
                // Check whether the file that holds a list of customers exists
                if (fiCustomers.Exists)
                {
                    // If that exists, open it and pass it to a FileStream object
                    using (FileStream? fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        // Get the list of customers and pass the records to the XML DOM object created earlier
                        xdCustomers.Load(fsCustomers);
                        // Create an XmlNodeList list of customers using XPath
                        XmlNodeList xnlCustomers = xdCustomers.DocumentElement!.SelectNodes("//account-number[.='" + mtbAccountNumber.Text + "']")!;
    
                        // Check each node of the XML record and display its values in each Windows control on the form
                        foreach (XmlNode xnCustomer in xnlCustomers)
                        {
                            //mtbAccountNumber.Text = xnCustomer.NextSibling!.InnerText;
                            txtAccountName.Text = xnCustomer.NextSibling!.InnerText;
                            txtMeterNumber.Text = xnCustomer.NextSibling.NextSibling!.InnerText;
                            strMeterNumber = xnCustomer.NextSibling.NextSibling!.InnerText;
                            txtAccountType.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;
                        }
                    }
                }
    
                // Create an XML DOM object for the water meters records
                XmlDocument xdWaterMeters = new XmlDocument();
                // Declare a variable for a file that holds the list of water meters
                string? strWaterMeters = @"C:\Stellar Water Point6\WaterMeters.xml";
    
                // Create a FileInfo object for the customers
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                // Check whether the file that holds a list of water meters exists
                if (fiWaterMeters.Exists)
                {
                    // Get the list of water meters and pass the records to the XML DOM object
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        // Get the list of water meters and pass the records to the XML DOM object
                        xdWaterMeters.Load(fsWaterMeters);
                        // Create an XmlNodeList list of water meters using XPath
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + strMeterNumber + "']")!;
    
                        // Check each node of the XML record
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            /* Get the values for the water meter.
                             * Create a sentence and display it in the Meter Details text box. */
                            txtMeterDetails.Text = xnWaterMeter.NextSibling!.InnerText + " " +
                                                   xnWaterMeter.NextSibling.NextSibling!.InnerText + " (Meter Size: " +
                                                   xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText + ")";
                        }
                    }
                }
            }
        }
    }
  10. In the Solution Explorer, below the Customers folder, double-click Central.cs
  11. From the Toolbox, add two buttons to the form below the list view and on the right side of the Edit Customer Acount button
  12. Change the characteristics of the new buttons as follows:

    Stellar Water Point - Water Meters

    Control (Name) Other Properties
    ListView List View lvwCustomers
    Button Button btnDeleteCustomerAcount &Delete Customer Acount...
    Anchor: Bottom, Right
    Button Button btnClose &Close
    Anchor: Bottom, Right
  13. Double-click the Delete Customer Account button
  14. Return to the Central form of the water meters and double-click the Close button
  15. Change the document as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.Customers
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowCustomers()
            {
                int i = 1;
    
                lvwCustomers.Items.Clear();
    
                XmlDocument xdCustomers = new XmlDocument();
                string? strCustomers = @"C:\Stellar Water Point6\Customers.xml";
    
                FileInfo? fiCustomers = new FileInfo(strCustomers);
    
                if (fiCustomers.Exists)
                {
                    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)
                        {
                            ListViewItem lviCustomer = new ListViewItem(i.ToString());
    
                            lviCustomer.SubItems.Add(xnCustomer.FirstChild!.InnerText);   // Account #
                            lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling!.InnerText);   // Account Name
                            lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling.NextSibling!.InnerText); // Meter #
                            lviCustomer.SubItems.Add(xnCustomer.FirstChild.NextSibling.NextSibling.NextSibling!.InnerText);   // Account Type
                            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 Central_Load(object sender, EventArgs e)
            {
                ShowCustomers();
            }
    
            private void btnCreateCustomerAccount_Click(object sender, EventArgs e)
            {
                Create create = new Create();
    
                if (create.ShowDialog() == DialogResult.OK)
                {
                    /* Make sure the user provides an account number for the new account. 
                     * If not, don't create the account. */
                    if (string.IsNullOrEmpty(create.mtbAccountNumber.Text))
                    {
                        MessageBox.Show("You must provide an account number for the new customer. " +
                                        "Otherwise, the account cannot be created.",
                                        "Stellar Water Point",
                                        MessageBoxButtons.OK, MessageBoxIcon.Information);
    
                        return;
                    }
    
                    /* If the meter details text box is empty, it means the user didn't enter
                     * a meter number, in which case there is no water meter associated 
                     * with the account. The account cannot be created. */
                    if (string.IsNullOrEmpty(create.txtMeterDetails.Text))
                    {
                        MessageBox.Show("You must enter a water meter to associate with a new customer's account.",
                                        "Stellar Water Point",
                                        MessageBoxButtons.OK, MessageBoxIcon.Information);
    
                        return;
                    }
    
                    // Create a FileInfo object that will be used to manage a file
                    FileInfo? fiCustomers = null;
                    // Start a Stream object that will be used to manage a file
                    FileStream? fsCustomers = null;
                    // Create an XML Dom
                    XmlDocument xdCustomers = new XmlDocument();
                    // Declare a string variable for the file that contains a list of customers
                    string? strCustomers = @"C:\Stellar Water Point6\Customers.xml";
    
                    // Pass the file of customers to the FileInfo object that was started
                    fiCustomers = new FileInfo(strCustomers);
    
                    // Find out whether that file was already created
                    if (fiCustomers.Exists)
                    {
                        /* If that file was already created, open it through 
                         * the Stream object that was previously initiated. */
                        using (fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open,
                                                            FileAccess.Read, FileShare.Read))
                        {
                            // Pass the Stream object to the XML Dom that was previously created.
                            xdCustomers.Load(fsCustomers);
                        }
                    }
                    else
                    {
                        /* If the file of customers was not created already, start by 
                         * initializing the Stream object that was previously initiated. */
                        using (fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Create, FileAccess.Write, FileShare.Write))
                        {
                            // Create a root to start the XML file
                            xdCustomers.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                                                "<customers></customers>");
                            // Once the file has been started, save it
                            xdCustomers.Save(fsCustomers);
                        }
                    }
    
                    // Now that we have an XML file for customers, open it
                    using (fsCustomers = new FileStream(fiCustomers.FullName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
                    {
                        /* We want to create an XML element to be added to the XML file.
                         * To start, create an XML element named "customer". */
                        XmlElement xeCustomer = xdCustomers.CreateElement("customer");
    
                        // Create/Format the child nodes of the "customer" element
                        xeCustomer.InnerXml = "<account-number>" + create.mtbAccountNumber.Text + "</account-number>" +
                                              "<account-name>" + create.txtAccountName.Text + "</account-name>" +
                                              "<meter-number>" + create.mtbMeterNumber.Text + "</meter-number>" +
                                              "<account-type>" + create.cbxAccountsTypes.Text + "</account-type>" +
                                              "<address>" + create.txtAddress.Text + "</address>" +
                                              "<city>" + create.txtCity.Text + "</city>" +
                                              "<county>" + create.txtCounty.Text + "</county>" +
                                              "<state>" + create.txtState.Text + "</state>" +
                                              "<zip-code>" + create.mtbZIPCode.Text + "</zip-code>";
                        xdCustomers.DocumentElement!.AppendChild(xeCustomer);
                        xdCustomers.Save(fsCustomers);
                    }
                }
    
                ShowCustomers();
            }
    
            private void ViewCustomerAccount_Click(object sender, EventArgs e)
            {
                Details det = new Details();
    
                det.ShowDialog();
            }
    
            private void btnEditWaterMeter_Click(object sender, EventArgs e)
            {
                // This is the form that will be used to update a customer record
                Editor editor = new();
                // Create an XML DOM object
                XmlDocument xdCustomers = new XmlDocument();
                // Prepare the path and name of the file that holds a list of customers 
                string? strCustomers = @"C:\Stellar Water Point6\Customers.xml";
    
                /* Display the Editor form.
                 * Find out if the user clicked the Update Customer Account button when closing the Editor dialog box. */
                if (editor.ShowDialog() == DialogResult.OK)
                {
                    // Get the customers records and store them in the above XML DOM object
                    xdCustomers.Load(strCustomers);
    
                    /* Create an XmlNodeList list that reprensents the XML elements from the list of customers.
                     * Call the XML DOM's GetElementsByTagName() method. 
                     * To use the account number elements as references, pass the name of the Account # element as argument. */
                    XmlNodeList xnlCustomers = xdCustomers.DocumentElement!.GetElementsByTagName("account-number");
    
                    // Visit each XML element of the list of customers
                    foreach (XmlNode xnCustomer in xnlCustomers)
                    {
                        /* When you get to an element, find out if the value of it Account Number is 
                         * the same as the account number the user typed in the form. If that's the case, 
                         * change the value of each node of that element, using the values from the form. */
                        if (xnCustomer.InnerText.Contains(editor.mtbAccountNumber.Text))
                        {
                            xnCustomer.ParentNode!.InnerXml = "<account-number>" + editor.mtbAccountNumber.Text + "</account-number>" +
                                                  "<account-name>" + editor.txtAccountName.Text + "</account-name>" +
                                                  "<meter-number>" + editor.mtbMeterNumber.Text + "</meter-number>" +
                                                  "<account-type>" + editor.cbxAccountsTypes.Text + "</account-type>" +
                                                  "<address>" + editor.txtAddress.Text + "</address>" +
                                                  "<city>" + editor.txtCity.Text + "</city>" +
                                                  "<county>" + editor.txtCounty.Text + "</county>" +
                                                  "<state>" + editor.txtState.Text + "</state>" +
                                                  "<zip-code>" + editor.mtbZIPCode.Text + "</zip-code>";
    
                            // After updating the elements, save the updated file
                            xdCustomers.Save(strCustomers);
                            // After saving the file, stop searching
                            break;
                        }
                    }
                }
    
                /* Now that the user has closed the Editor dialog box (and probably updated the XML file), 
                 * redisplay the list of customers.*/
                ShowCustomers();
            }
    
            private void btnDeleteCustomerAcount_Click(object sender, EventArgs e)
            {
                // Here is the dialog box that the user will use to locate and delete a customer account
                Delete delete = new();
                // Create an XML DOM object
                XmlDocument xdCustomers = new XmlDocument();
                // Specify the file that holds a database of customers
                string? strCustomers = @"C:\Stellar Water Point6\Customers.xml";
    
                /* Open the Delete dialog box.
                 * Find out if the user clicked the Delete Customer Account button to close the Delete dialog box. */
                if (delete.ShowDialog() == DialogResult.OK)
                {
                    // If there is no file for the list of customers, don't do nothing
                    if (!File.Exists(strCustomers))
                    {
                        MessageBox.Show("There is no file for the customers accounts in the system.",
                                        "Stellar Water Point",
                                        MessageBoxButtons.OK, MessageBoxIcon.Information);
                        return;
                    }
                    // If the user didn't provide a valid account number, don't do nothing
                    if (string.IsNullOrEmpty(delete.mtbAccountNumber.Text))
                    {
                        MessageBox.Show("You must type an account number for the customer whose account you want to delete one.",
                                        "Stellar Water Point", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        return;
                    }
    
                    // Open the file of customers records and put those records in our XML DOM object
                    xdCustomers.Load(strCustomers);
    
                    /* Create an XmlNodeList list of the customers records. 
                     * Use the Account Number node as reference. */
                    XmlNodeList xnlCustomers = xdCustomers.DocumentElement!.GetElementsByTagName("account-number");
    
                    // Check each customer record as an XML element
                    foreach (XmlNode xnCustomer in xnlCustomers)
                    {
                        /* When you reach an element, find out whether its value is 
                         * the same as the account number the user typed on the form. */
                        if (xnCustomer.InnerText == delete.mtbAccountNumber.Text)
                        {
                            // If you find a matching record, find whether the user really wants to delete the record.
                            if (MessageBox.Show("Are you sure you want to remove this customer's account from the system?",
                                            "Stellar Water Point",
                                            MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                            {
                                // If the user really wants to delete the record, delete it...
                                xdCustomers.DocumentElement.RemoveChild(xnCustomer.ParentNode!);
                                // and stop searching
                                break;
                            }
                        }
                    }
    
                    // After removing the record, save the new version of the file 
                    xdCustomers.Save(strCustomers);
                }
    
                /* Now that the user has closed the Delete dialog box (and probably deleted the XML file), 
                 * redisplay the list of customers.*/
                ShowCustomers();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  16. To execute the application, on the main menu, click Debug -> Start Without Debugging:

    Stellar Water Point - Water Meters

  17. On the Central form, click the Customers button:

    Stellar Water Point - Customers

  18. On the Central form of the customers, click the Delete Customer Account button:

    Stellar Water Point - Customer Account Deletion

  19. In the Account # text box, type 7080-583-5947
  20. Click the Find Customer Account button:

    Stellar Water Point - Customer Account Deletion

  21. Click the Delete Customer Account button
  22. Read the text on the message box.
    On the message box, click Yes

    Stellar Water Point - Customers

  23. Close the forms and return to your programming environment
  24. From the Windows Explorer, open the Customers.xml file
  25. Replace the content of the file with the provided file
  26. Save the file
  27. Return to your programming environment

Water Bills

Introduction

A water bill is a summary that indicates how much water a customer consumed and the value of that consumption. Our application will include a form to process a water bill. We will use another form that can be used to review an existing water bill. We will use another form to change or update a water bill that was previously processed. Finally, we will have a form that can be used to delete a water bill. In previous sections, we provided one Central form for the water meters and another Central form for the Customers. Those Central forms allow the user to navigate to the forms related to a section. Those sections included a form that provides a list of records. Because a water bill has too many values, we will not create a form that presents a list of water bills.

Practical LearningPractical Learning: Preparing Bills

  1. In the Solution Explorer, right-click StellarWaterPoint1 -> Add -> New Folder
  2. Type WaterBills as the name of the folder

A Water Bill

Our application will have a list of water meters. A record for each water meter must be created. To make this happen, we will equip the application with an appropriate form.

Practical LearningPractical Learning: Processing a Water Bill

  1. To create a form, in the Solution Explorer, right-click WaterBills -> Add -> Form (Windows Forms)...
  2. Type Create as the name of the file
  3. Click Add
  4. Design the form as follows:

    Stellar Water Point - New Water Bill

    Control (Name) Text Other Properties
    Label Label   Water Bill #:  
    TextBox Text Box txtBillNumber    
    GroupBox Label   Customer Information  
    Label Label   Account #:  
    MaskedTextBox Masked Text Box mtbAccountNumber   Masked: 0000-000-0000
    Button Button btnFindCustomerAccount Find Customer Account  
    Label Label   Customer Name:  
    TextBox Text Box txtCustomerName    
    Label Label   Address:  
    TextBox Text Box txtAddress    
    TextBox Text Box txtCity    
    TextBox Text Box txtCounty    
    TextBox Text Box txtState    
    MaskedTextBox Masked Text Box mtbZIPCode   Masked: Zip-Code
    Label Label   ______________________________________________  
    Label Label   Meter Details:  
    TextBox Text Box txtMeterDetails Modifiers: Public  
    GroupBox Label   Meter Reading  
    Label Label   Meter Reading Start Date:  
    DateTimePicker Date Time Picker dtpMeterReadingStartDate  
    Label Label   Meter Reading End Date:  
    DateTimePicker Date Time Picker dtpMeterReadingEndDate  
    Label Label   Counter Reading Start:  
    TextBox Text Box txtCounterReadingStart    
    Label Label   Counter Reading End:  
    TextBox Text Box txtCounterReadingEnd    
    Button Button btnEvaluateWaterBill Evaluate Water Bill  
    GroupBox Label   Meter Result  
    Label Label   Billing Days:  
    TextBox Text Box txtBillingDays   TextAlign: Right
    Label Label   Total Gallons:  
    TextBox Text Box txtTotalGallons   TextAlign: Right
    Label Label   Total CCF:  
    TextBox Text Box txtTotalCCF   TextAlign: Right
    Label Label   First Tier Consumption:  
    TextBox Text Box txtFirstTierConsumption   TextAlign: Right
    Label Label   Second Tier:  
    TextBox Text Box txtSecondTierConsumption   TextAlign: Right
    Label Label   Last Tier:  
    TextBox Text Box txtLastTierConsumption   TextAlign: Right
    GroupBox Label   Consumption Charges  
    Label Label   Water Charges:  
    TextBox Text Box txtWaterCharges   TextAlign: Right
    Label Label   Sewer Charges:  
    TextBox Text Box txtSewerCharges   TextAlign: Right
    Label Label   Environment Charges:  
    TextBox Text Box txtEnvironmentCharges   TextAlign: Right
    Label Label   Total Charges:  
    TextBox Text Box txtTotalCharges   TextAlign: Right
    GroupBox Label   Taxes  
    Label Label   Local Taxes:  
    TextBox Text Box txtLocalTaxes   TextAlign: Right
    Label Label   State Taxes:  
    TextBox Text Box txtStateTaxes   TextAlign: Right
    GroupBox Label   Water Bill Payment  
    Label Label   Payment Due Date:  
    DateTimePicker Date Time Picker dtpPaymentDueDate  
    Label Label   Amount Due:  
    TextBox Text Box txtAmountDue   TextAlign: Right
    Label Label   Late Payment Due Date:  
    DateTimePicker Date Time Picker dtpLatePaymentDueDate  
    Label Label   Late Amount Due:  
    TextBox Text Box txtLateAmountDue   TextAlign: Right
    Button Button btnSaveWaterBill Save Water Bill  
    Button Button btnClose Close  
  5. On the form, double-click the Find Customer Account button
  6. Change the document as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.WaterBills
    {
        public partial class Create : Form
        {
            public Create()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                XmlDocument xdCustomers = new XmlDocument();
                string? strCustomers    = @"C:\Stellar Water Point6\Customers.xml";
    
                FileInfo? fiCustomers   = new FileInfo(strCustomers);
    
                string strMeterNumber   = string.Empty;
    
                if (fiCustomers.Exists)
                {
                    using (FileStream? fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdCustomers.Load(fsCustomers);
                        XmlNodeList xnlCustomers = xdCustomers.DocumentElement!.SelectNodes("//account-number[.='" + mtbAccountNumber.Text + "']")!;
    
                        foreach (XmlNode xnCustomer in xnlCustomers)
                        {
                            txtAccountName.Text = xnCustomer.NextSibling!.InnerText;
                            strMeterNumber      = xnCustomer.NextSibling.NextSibling!.InnerText;
                            txtAccountType.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;
                        }
                    }
                }
    
                XmlDocument xdWaterMeters = new XmlDocument();
                string? strWaterMeters = @"C:\Stellar Water Point6\WaterMeters.xml";
    
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                if (fiWaterMeters.Exists)
                {
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdWaterMeters.Load(fsWaterMeters);
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + strMeterNumber + "']")!;
    
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            txtMeterDetails.Text = xnWaterMeter.NextSibling!.InnerText + " " +
                                                   xnWaterMeter.NextSibling.NextSibling!.InnerText + " (Meter Size: " +
                                                   xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText + ")";
                        }
                    }
                }
            }
        }
    }
  7. Return to the Water Bills - Create form and double-click the Meter Reading End Date date time picker
  8. Implement the event as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.WaterBills
    {
        public partial class Create : Form
        {
            public Create()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void dtpMeterReadingEndDate_ValueChanged(object sender, EventArgs e)
            {
                TimeSpan tsDays = dtpMeterReadingEndDate.Value - dtpMeterReadingStartDate.Value;
    
                txtBillingDays.Text = (tsDays.Days + 1).ToString();
            }
        }
    }
  9. Return to the Water Bills - Create form and double-click the Evaluate Water Bill button
  10. Implement the event as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.WaterBills
    {
        public partial class Create : Form
        {
            public Create()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void dtpMeterReadingEndDate_ValueChanged(object sender, EventArgs e)
            {
                . . .
            }
    
            (double a, double b, double c) CalculateTiers(string acnt, double total)
            {
                (double tier1, double tier2, double tier3) results = (0.00, 0.00, 0.00);
    
                switch (acnt)
                {
                    case "RES":
                        results.tier1 = total * 41.50 / 10000.00;
                        results.tier2 = total * 32.50 / 10000.00;
                        results.tier3 = total * 26.00 / 10000.00;
                        break;
                    case "SGO":
                        results.tier1 = total * 46 / 10000;
                        results.tier2 = total * 50 / 10000;
                        results.tier3 = total * 4 / 10000;
                        break;
                    case "BUS":
                        results.tier1 = total * 45 / 10000;
                        results.tier2 = total * 30 / 10000;
                        results.tier3 = total * 25 / 10000;
                        break;
                    case "UUO":
                        results.tier1 = total * 25 / 10000;
                        results.tier2 = total * 35 / 10000;
                        results.tier3 = total * 40 / 10000;
                        break;
                    case "WAT":
                        results.tier1 = total * 50 / 10000;
                        results.tier2 = total * 40 / 10000;
                        results.tier3 = total * 10 / 10000;
                        break;
                    default:
                        results.tier1 = total * (48.00 / 10000.00);
                        results.tier2 = total * (32.00 / 10000.00);
                        results.tier3 = total * (20.00 / 10000.00);
                        break;
                }
    
                return results;
            }
    
            private double CalculateSewerCharges(string acnt, double total)
            {
                double result;
    
                if (acnt == "RES")
                {
                    result = total * 6.826941 / 100;
                }
                else if (acnt == "SGO")
                {
                    result = total * 4.162522 / 100;
                }
                else if (acnt == "BUS")
                {
                    result = total * 8.3136 / 100;
                }
                else if (acnt == "UUO")
                {
                    result = total * 10.6247 / 100;
                }
                else if (acnt == "WAT")
                {
                    result = total * 12.0535 / 100;
                }
                else // if (acnt == "OTH)"
                {
                    result = total * 9.2065 / 100;
                }
    
                return result;
            }
    
            private double CalculateEnvironmentCharges(string acnt, double total)
            {
                double result;
    
                switch(acnt)
                {
                    case "RES":
                        result = total * 0.022724;
                        break;
                    case "SGO":
                        result = total * 0.118242;
                        break;
                    case "BUS":
                        result = total * 0.161369;
                        break;
                    case "UUO":
                        result = total * 0.082477;
                        break;
                    case "WAT":
                        result = total * 0.413574;
                        break;
                    default:
                        result = total * 0.221842;
                        break;
                }
    
                return result;
            }
    
            private double CalculateServiceCharges(string acnt, double total)
            {
                switch (acnt)
                {
                    case "RES":
                        return total * 0.145748;
                    case "SGO":
                        return total * 0.102246;
                    case "BUS":
                        return total * 0.242627;
                    case "UUO":
                        return total * 0.186692;
                    case "WAT":
                        return total * 0.412628;
                    default:
                        return total * 0.210248;
                }
            }
    
            private double CalculateLocalTaxes(string acnt, double total) => acnt switch
            {
                "RES" => total * 0.031574,
                "SGO" => total * 0.035026,
                "BUS" => total * 0.122517,
                "UUO" => total * 0.105737,
                "WAT" => total * 0.153248,
                _ => total * 0.125148
            };
    
            private double CalculateStateTaxes(string acnt, double total) => acnt switch
            {
                "RES" => total * 0.016724,
                "SGO" => total * 0.008779,
                "BUS" => total * 0.042448,
                "UUO" => total * 0.067958,
                "WAT" => total * 0.081622,
                _ => total * 0.013746
            };
    
            private DateTime SetPaymentDueDate(string acnt, DateTime date)
            {
                TimeSpan tsPaymentDueDate = new TimeSpan(1, 0, 0, 0);
    
                if (acnt == "RES")
                {
                    tsPaymentDueDate = new TimeSpan(15, 0, 0, 0);
                }
                else if (acnt == "SGO")
                {
                    tsPaymentDueDate = new TimeSpan(20, 0, 0, 0);
                }
                else if (acnt == "BUS")
                {
                    tsPaymentDueDate = new TimeSpan(30, 0, 0, 0);
                }
                else if (acnt == "UUO")
                {
                    tsPaymentDueDate = new TimeSpan(15, 0, 0, 0);
                }
                else if (acnt == "WAT")
                {
                    tsPaymentDueDate = new TimeSpan(40, 0, 0, 0);
                }
                else
                {
                    tsPaymentDueDate = new TimeSpan(35, 0, 0, 0);
                }
    
                return date + tsPaymentDueDate;
            }
    
            private DateTime SetLatePaymentDueDate(string acnt, DateTime date)
            {
                switch (acnt)
                {
                    case "RES":
                        return date + new TimeSpan(30, 0, 0, 0);
                    case "SGO":
                        return date + new TimeSpan(40, 0, 0, 0);
                    case "BUS":
                        return date + new TimeSpan(50, 0, 0, 0);
                    case "UUO":
                        return date + new TimeSpan(60, 0, 0, 0);
                    case "WAT":
                        return date + new TimeSpan(65, 0, 0, 0);
                    default:
                        return date + new TimeSpan(45, 0, 0, 0);
                }
            }
    
            private double CalculateLateAmountDue(string acnt, double amt) => acnt switch
            {
                "RES" => amt + 8.95,
                "SGO" => amt + (amt / 4.575),
                "BUS" => amt + (amt / 12.315),
                "UUO" => amt + (amt / 7.425),
                "WAT" => amt + (amt / 15.225),
                _     => amt + (amt / 6.735)
            };
    
            private void btnEvaluateWaterBill_Click(object sender, EventArgs e)
            {
                double counterStart = 0, counterEnd = 0;
    
                try
                {
                    counterStart = double.Parse(txtCounterReadingStart.Text);
                }
                catch (FormatException feCRStart)
                {
                    MessageBox.Show("There was a problem with the value of the " +
                                    "Counter Reading Start. The error produced is: " + feCRStart.Message,
                                    "Stellar Water Point", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
    
                try
                {
                    counterEnd = double.Parse(txtCounterReadingEnd.Text);
                }
                catch (FormatException feCREnd)
                {
                    MessageBox.Show("There was a problem with the value of the " +
                                    "Counter Reading End. The error produced is: " + feCREnd.Message,
                                    "Stellar Water Point", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
    
                double consumption            = counterEnd - counterStart;
                double gallons                = consumption * 748.05;
    
                string strAccountType         = txtAccountType.Text[..3];
    
                (double first, double second, double last) tiers = CalculateTiers(strAccountType, gallons);
    
                double waterCharges           = tiers.first + tiers.second + tiers.last;
                double sewerCharges           = CalculateSewerCharges(strAccountType, waterCharges);
                double envCharges             = CalculateEnvironmentCharges(strAccountType, waterCharges);
                double srvCharges             = CalculateServiceCharges(strAccountType, waterCharges);
                double totalCharges           = waterCharges + sewerCharges + envCharges + srvCharges;
                double localTaxes             = CalculateLocalTaxes(strAccountType, waterCharges);
                double stateTaxes             = CalculateStateTaxes(strAccountType, waterCharges);
                double amtDue                 = totalCharges + localTaxes + stateTaxes;
    
                txtTotalHCF.Text              = consumption.ToString();
                txtTotalGallons.Text          = ((int)(Math.Ceiling(gallons))).ToString();
                txtFirstTierConsumption.Text  = tiers.first.ToString("F");
                txtSecondTierConsumption.Text = tiers.second.ToString("F");
                txtLastTierConsumption.Text   = tiers.last.ToString("F");
                txtWaterCharges.Text          = waterCharges.ToString("F");
                txtSewerCharges.Text          = sewerCharges.ToString("F");
                txtEnvironmentCharges.Text    = envCharges.ToString("F");
                txtServiceCharges.Text        = srvCharges.ToString("F");
                txtTotalCharges.Text          = totalCharges.ToString("F");
                txtLocalTaxes.Text            = localTaxes.ToString("F");
                txtStateTaxes.Text            = stateTaxes.ToString("F");
                dtpPaymentDueDate.Value       = SetPaymentDueDate(strAccountType, dtpMeterReadingEndDate.Value);
                txtAmountDue.Text             = amtDue.ToString("F");
                dtpLatePaymentDueDate.Value   = SetLatePaymentDueDate(strAccountType, dtpMeterReadingEndDate.Value);
                txtLateAmountDue.Text         = CalculateLateAmountDue(strAccountType, amtDue).ToString("F");
            }
        }
    }
  11. Return to the Water Bills - Create form and double-click the Save Water Bill button
  12. Return to the form and double-click the Close button
  13. Finalize the document as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.WaterBills
    {
        public partial class Create : Form
        {
            public Create()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                XmlDocument xdCustomers = new XmlDocument();
                string? strCustomers    = @"C:\Stellar Water Point6\Customers.xml";
    
                FileInfo? fiCustomers   = new FileInfo(strCustomers);
    
                string strMeterNumber   = string.Empty;
    
                if (fiCustomers.Exists)
                {
                    using (FileStream? fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdCustomers.Load(fsCustomers);
                        XmlNodeList xnlCustomers = xdCustomers.DocumentElement!.SelectNodes("//account-number[.='" + mtbAccountNumber.Text + "']")!;
    
                        foreach (XmlNode xnCustomer in xnlCustomers)
                        {
                            txtAccountName.Text = xnCustomer.NextSibling!.InnerText;
                            strMeterNumber      = xnCustomer.NextSibling.NextSibling!.InnerText;
                            txtAccountType.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;
                        }
                    }
                }
    
                XmlDocument xdWaterMeters = new XmlDocument();
                string? strWaterMeters = @"C:\Stellar Water Point6\WaterMeters.xml";
    
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                if (fiWaterMeters.Exists)
                {
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdWaterMeters.Load(fsWaterMeters);
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + strMeterNumber + "']")!;
    
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            txtMeterDetails.Text = xnWaterMeter.NextSibling!.InnerText + " " +
                                                   xnWaterMeter.NextSibling.NextSibling!.InnerText + " (Meter Size: " +
                                                   xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText + ")";
                        }
                    }
                }
            }
    
            private void dtpMeterReadingEndDate_ValueChanged(object sender, EventArgs e)
            {
                TimeSpan tsDays = dtpMeterReadingEndDate.Value - dtpMeterReadingStartDate.Value;
    
                txtBillingDays.Text = (tsDays.Days + 1).ToString();
            }
    
            (double a, double b, double c) CalculateTiers(string acnt, double total)
            {
                (double tier1, double tier2, double tier3) results = (0.00, 0.00, 0.00);
    
                if (acnt == "RES")
                {
                    results.tier1 = total * 41.50 / 10000.00;
                    results.tier2 = total * 32.50 / 10000.00;
                    results.tier3 = total * 26.00 / 10000.00;
                }
                else if (acnt == "SGO")
                {
                    results.tier1 = total * 46 / 10000;
                    results.tier2 = total * 50 / 10000;
                    results.tier3 = total *  4 / 10000;
                }
                else if (acnt == "BUS")
                {
                    results.tier1 = total * 45 / 10000;
                    results.tier2 = total * 30 / 10000;
                    results.tier3 = total * 25 / 10000;
                }
                else if (acnt == "UUO")
                {
                    results.tier1 = total * 25 / 10000;
                    results.tier2 = total * 35 / 10000;
                    results.tier3 = total * 40 / 10000;
                }
                else if (acnt == "WAT")
                {
                    results.tier1 = total * 50 / 10000;
                    results.tier2 = total * 40 / 10000;
                    results.tier3 = total * 10 / 10000;
                }
                else
                {
                    results.tier1 = total * (48.00 / 10000.00);
                    results.tier2 = total * (32.00 / 10000.00);
                    results.tier3 = total * (20.00 / 10000.00);
                }
    
                return results;
            }
    
            private double CalculateSewerCharges(string acnt, double total)
            {
                double result;
    
                if (acnt == "RES")
                {
                    result = total * 6.826941 / 100;
                }
                else if (acnt == "SGO")
                {
                    result = total * 4.162522 / 100;
                }
                else if (acnt == "BUS")
                {
                    result = total * 8.3136 / 100;
                }
                else if (acnt == "UUO")
                {
                    result = total * 10.6247 / 100;
                }
                else if (acnt == "WAT")
                {
                    result = total * 12.0535 / 100;
                }
                else // if (acnt == "OTH)"
                {
                    result = total * 9.2065 / 100;
                }
    
                return result;
            }
    
            private double CalculateEnvironmentCharges(string acnt, double total)
            {
                double result;
    
                switch(acnt)
                {
                    case "RES":
                        result = total * 0.022724;
                        break;
                    case "SGO":
                        result = total * 0.118242;
                        break;
                    case "BUS":
                        result = total * 0.161369;
                        break;
                    case "UUO":
                        result = total * 0.082477;
                        break;
                    case "WAT":
                        result = total * 0.413574;
                        break;
                    default:
                        result = total * 0.221842;
                        break;
                }
    
                return result;
            }
    
            private double CalculateServiceCharges(string acnt, double total)
            {
                switch (acnt)
                {
                    case "RES":
                        return total * 0.145748;
                    case "SGO":
                        return total * 0.102246;
                    case "BUS":
                        return total * 0.242627;
                    case "UUO":
                        return total * 0.186692;
                    case "WAT":
                        return total * 0.412628;
                    default:
                        return total * 0.210248;
                }
            }
    
            private double CalculateLocalTaxes(string acnt, double total) => acnt switch
            {
                "RES" => total * 0.031574,
                "SGO" => total * 0.035026,
                "BUS" => total * 0.122517,
                "UUO" => total * 0.105737,
                "WAT" => total * 0.153248,
                _ => total * 0.125148
            };
    
            private double CalculateStateTaxes(string acnt, double total) => acnt switch
            {
                "RES" => total * 0.016724,
                "SGO" => total * 0.008779,
                "BUS" => total * 0.042448,
                "UUO" => total * 0.067958,
                "WAT" => total * 0.081622,
                _ => total * 0.013746
            };
    
            private DateTime SetPaymentDueDate(string acnt, DateTime date)
            {
                TimeSpan tsPaymentDueDate = new TimeSpan(1, 0, 0, 0);
    
                if (acnt == "RES")
                {
                    tsPaymentDueDate = new TimeSpan(15, 0, 0, 0);
                }
                else if (acnt == "SGO")
                {
                    tsPaymentDueDate = new TimeSpan(20, 0, 0, 0);
                }
                else if (acnt == "BUS")
                {
                    tsPaymentDueDate = new TimeSpan(30, 0, 0, 0);
                }
                else if (acnt == "UUO")
                {
                    tsPaymentDueDate = new TimeSpan(15, 0, 0, 0);
                }
                else if (acnt == "WAT")
                {
                    tsPaymentDueDate = new TimeSpan(40, 0, 0, 0);
                }
                else
                {
                    tsPaymentDueDate = new TimeSpan(35, 0, 0, 0);
                }
    
                return date + tsPaymentDueDate;
            }
    
            private DateTime SetLatePaymentDueDate(string acnt, DateTime date)
            {
                switch (acnt)
                {
                    case "RES":
                        return date + new TimeSpan(30, 0, 0, 0);
                    case "SGO":
                        return date + new TimeSpan(40, 0, 0, 0);
                    case "BUS":
                        return date + new TimeSpan(50, 0, 0, 0);
                    case "UUO":
                        return date + new TimeSpan(60, 0, 0, 0);
                    case "WAT":
                        return date + new TimeSpan(65, 0, 0, 0);
                    default:
                        return date + new TimeSpan(45, 0, 0, 0);
                }
            }
    
            private double CalculateLateAmountDue(string acnt, double amt) => acnt switch
            {
                "RES" => amt + 8.95,
                "SGO" => amt + (amt / 4.575),
                "BUS" => amt + (amt / 12.315),
                "UUO" => amt + (amt / 7.425),
                "WAT" => amt + (amt / 15.225),
                _     => amt + (amt / 6.735)
            };
    
            private void btnEvaluateWaterBill_Click(object sender, EventArgs e)
            {
                double counterStart = 0, counterEnd = 0;
    
                try
                {
                    counterStart = double.Parse(txtCounterReadingStart.Text);
                }
                catch (FormatException feCRStart)
                {
                    MessageBox.Show("There was a problem with the value of the " +
                                    "Counter Reading Start. The error produced is: " + feCRStart.Message,
                                    "Stellar Water Point", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
    
                try
                {
                    counterEnd = double.Parse(txtCounterReadingEnd.Text);
                }
                catch (FormatException feCREnd)
                {
                    MessageBox.Show("There was a problem with the value of the " +
                                    "Counter Reading End. The error produced is: " + feCREnd.Message,
                                    "Stellar Water Point", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
    
                double consumption            = counterEnd - counterStart;
                double gallons                = consumption * 748.05;
    
                string strAccountType         = txtAccountType.Text[..3];
    
                (double first, double second, double last) tiers = CalculateTiers(strAccountType, gallons);
    
                double waterCharges           = tiers.first + tiers.second + tiers.last;
                double sewerCharges           = CalculateSewerCharges(strAccountType, waterCharges);
                double envCharges             = CalculateEnvironmentCharges(strAccountType, waterCharges);
                double srvCharges             = CalculateServiceCharges(strAccountType, waterCharges);
                double totalCharges           = waterCharges + sewerCharges + envCharges + srvCharges;
                double localTaxes             = CalculateLocalTaxes(strAccountType, waterCharges);
                double stateTaxes             = CalculateStateTaxes(strAccountType, waterCharges);
                double amtDue                 = totalCharges + localTaxes + stateTaxes;
    
                txtTotalHCF.Text              = consumption.ToString();
                txtTotalGallons.Text          = ((int)(Math.Ceiling(gallons))).ToString();
                txtFirstTierConsumption.Text  = tiers.first.ToString("F");
                txtSecondTierConsumption.Text = tiers.second.ToString("F");
                txtLastTierConsumption.Text   = tiers.last.ToString("F");
                txtWaterCharges.Text          = waterCharges.ToString("F");
                txtSewerCharges.Text          = sewerCharges.ToString("F");
                txtEnvironmentCharges.Text    = envCharges.ToString("F");
                txtServiceCharges.Text        = srvCharges.ToString("F");
                txtTotalCharges.Text          = totalCharges.ToString("F");
                txtLocalTaxes.Text            = localTaxes.ToString("F");
                txtStateTaxes.Text            = stateTaxes.ToString("F");
                dtpPaymentDueDate.Value       = SetPaymentDueDate(strAccountType, dtpMeterReadingEndDate.Value);
                txtAmountDue.Text             = amtDue.ToString("F");
                dtpLatePaymentDueDate.Value   = SetLatePaymentDueDate(strAccountType, dtpMeterReadingEndDate.Value);
                txtLateAmountDue.Text         = CalculateLateAmountDue(strAccountType, amtDue).ToString("F");
            }
    
            private void btnSaveWaterBill_Click(object sender, EventArgs e)
            {
                if (string.IsNullOrEmpty(txtBillNumber.Text))
                {
                    MessageBox.Show("You must type a bill number." +
                                    "Otherwise, the account cannot be saved.",
                                    "Stellar Water Point", MessageBoxButtons.OK);
                    return;
                }
    
                if (string.IsNullOrEmpty(txtCounterReadingStart.Text))
                {
                    MessageBox.Show("You must enter the start value of the water bill counter." +
                                    "Otherwise, the account cannot be saved.",
                                    "Stellar Water Point", MessageBoxButtons.OK);
                    return;
                }
    
                if (string.IsNullOrEmpty(mtbAccountNumber.Text))
                {
                    MessageBox.Show("You must type an account number of a customer." +
                                    "Otherwise, the account cannot be saved.",
                                    "Stellar Water Point", MessageBoxButtons.OK);
                    return;
                }
    
                FileStream? fsWaterBills = null;
                XmlDocument xdWaterBills = new XmlDocument();
                string strWaterBills     = @"C:\Stellar Water Point6\WaterBills.xml";
    
                FileInfo? fiWaterBills   = new FileInfo(strWaterBills);
    
                if (fiWaterBills.Exists)
                {
                    using (fsWaterBills = new FileStream(fiWaterBills.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdWaterBills.Load(fsWaterBills);
                    }
                }
                else
                {
                    using (fsWaterBills = new FileStream(fiWaterBills.FullName, FileMode.Create, FileAccess.Write, FileShare.Write))
                    {
                        xdWaterBills.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                                             "<water-bills></water-bills>");
                        xdWaterBills.Save(fsWaterBills);
                    }
                }
    
                using (fsWaterBills = new FileStream(fiWaterBills.FullName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
                {
                    XmlElement xeWaterBill = xdWaterBills.CreateElement("water-bill");
    
                    xeWaterBill.InnerXml = "<bill-number>"              + txtBillNumber.Text + "</bill-number>" +
                                           "<account-number>"           + mtbAccountNumber.Text + "</account-number>" +
                                           "<meter-reading-start-date>" + dtpMeterReadingStartDate.Value.ToShortDateString() + "</meter-reading-start-date>" +
                                           "<meter-reading-end-date>"   + dtpMeterReadingEndDate.Value.ToShortDateString() + "</meter-reading-end-date>" +
                                           "<billing-days>"             + txtBillingDays.Text + "</billing-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-tier-consumption>"   + txtFirstTierConsumption.Text + "</first-tier-consumption>" +
                                           "<second-tier-consumption>"  + txtSecondTierConsumption.Text + "</second-tier-consumption>" +
                                           "<last-tier-consumption>"    + txtLastTierConsumption.Text + "</last-tier-consumption>" +
                                           "<water-charges>"            + txtWaterCharges.Text + "</water-charges>" +
                                           "<sewer-charges>"            + txtSewerCharges.Text + "</sewer-charges>" +
                                           "<environment-charges>"      + txtEnvironmentCharges.Text + "</environment-charges>" +
                                           "<service-charges>"          + txtEnvironmentCharges.Text + "</service-charges>" +
                                           "<total-charges>"            + txtTotalCharges.Text + "</total-charges>" +
                                           "<state-taxes>"              + txtStateTaxes.Text + "</state-taxes>" +
                                           "<local-taxes>"              + txtLocalTaxes.Text + "</local-taxes>" +
                                           "<payment-due-date>"         + dtpPaymentDueDate.Value.ToShortDateString() + "</payment-due-date>" +
                                           "<amount-due>"               + txtAmountDue.Text + "</amount-due>" +
                                           "<late-payment-due-date>"    + dtpLatePaymentDueDate.Value.ToShortDateString() + "</late-payment-due-date>" +
                                           "<late-amount-due>"          + txtLateAmountDue.Text + "</late-amount-due>";
    
                    xdWaterBills.DocumentElement!.AppendChild(xeWaterBill);
                    xdWaterBills.Save(fsWaterBills);
                }
    
                Close();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }

A List of Water Bills

.

Practical LearningPractical Learning: Viewing Water Bills

  1. To create a form, in the Solution Explorer, right-click WaterBills -> Add -> Form (Windows Forms)...
  2. Type Central
  3. Click Add
  4. In the Toolbox, click the ListView button and click the form
  5. In the Properties window, change the characteristics of the list view as follows:
    Control (Name) Text Other Properties
    ListView List View lvwWaterBills   FullRowSelect: True
    GridLines: True
    View: Details
    Anchor: Top, Bottom, Left, Right
    Button Button btnCreateWaterBill Close &Create Water Bill...
  6. On the form, right-click the list view and click Edit Columns...
  7. Create the columns as follows:

    Stellar Water Point - Water Bills

    (Name) Text TextAlign Width
    colWaterBillId Id   40
    colBillNumber Bill # Center 80
    colAccountNumber Account # Center 150
    colStartDate Start Date Center 150
    colEndDate End Date Center 150
    colBillingDays Days Center  
    colCounterStart Counter Start Right 125
    colCounterEnd Counter End Right 125
    colTotalHCF Total HCF Right 100
    colGallons Gallons Right 80
    colPaymentDueDate Pmt Due Date Center 125
    colAmountDue Amt Due Right 90
  8. Click OK
  9. Doubte-click an unoccupied area of the form to generate its Load event
  10. Change the document as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.WaterBills
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowWaterBills()
            {
                lvwWaterBills.Items.Clear();
    
                XmlDocument xdWaterBills = new XmlDocument();
                string? strWaterBills = @"C:\Stellar Water Point6\WaterBills.xml";
    
                FileInfo? fiWaterBills = new FileInfo(strWaterBills);
    
                if (fiWaterBills.Exists)
                {
                    using (FileStream? fsWaterBills = new FileStream(fiWaterBills.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdWaterBills.Load(fsWaterBills);
                        XmlNodeList xnlWaterBills = xdWaterBills.DocumentElement!.ChildNodes;
    
                        int i = 1;
    
                        foreach (XmlNode xnWaterBill in xnlWaterBills)
                        {
                            ListViewItem lviWaterBill = new ListViewItem(i.ToString());
    
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild!.InnerText);
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling!.InnerText);
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling!.InnerText);
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling!.InnerText);
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText);
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.InnerText);
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.InnerText);
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText);
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText.ToString());
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText);
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText);
    
                            lvwWaterBills.Items.Add(lviWaterBill);
    
                            i++;
                        }
                    }
                }
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                ShowWaterBills();
            }
        }
    }
  11. Return to the Water Bills form and double-click the Create Water Bill button
  12. Implement the event as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.WaterBills
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowWaterBills()
            {
                lvwWaterBills.Items.Clear();
    
                XmlDocument xdWaterBills = new XmlDocument();
                string? strWaterBills = @"C:\Stellar Water Point6\WaterBills.xml";
    
                FileInfo? fiWaterBills = new FileInfo(strWaterBills);
    
                if (fiWaterBills.Exists)
                {
                    using (FileStream? fsWaterBills = new FileStream(fiWaterBills.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdWaterBills.Load(fsWaterBills);
                        XmlNodeList xnlWaterBills = xdWaterBills.DocumentElement!.ChildNodes;
    
                        int i = 1;
    
                        foreach (XmlNode xnWaterBill in xnlWaterBills)
                        {
                            ListViewItem lviWaterBill = new ListViewItem(i.ToString());
    
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild!.InnerText);   // Water Bill #
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling!.InnerText);   // Account Number
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling!.InnerText); // Meter Reading Start Date
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling!.InnerText);   // Meter Reading End Date
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText); // Billing Days
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.InnerText);  // Counter Reading Start
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.InnerText);   // Counter Reading End
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText);   // Total CCF
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText.ToString());   // Gallons
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText);   // Payment Due Date
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText);  // Amount Due
    
                            lvwWaterBills.Items.Add(lviWaterBill);
    
                            i++;
                        }
                    }
                }
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                ShowWaterBills();
            }
    
            private void btnCreateWaterBill_Click(object sender, EventArgs e)
            {
                Create create = new();
    
                create.ShowDialog();
    
                ShowWaterBills();
            }
        }
    }
  13. In the Solution Explorer, double-click WaterDistribution.cs to open the main form of the application
  14. From the Toolbox, add a button to the form
  15. Using the the Properties window, change the characteristics of the button as follows:

    Stellar Water Point

    Control (Name) Text Font
    Button Button btnWaterBills Water &Bills... Times New Roman, 24pt, style=Bold
    Button Button btnClose &Close Times New Roman, 24pt, style=Bold
  16. Double-click the Water &Bills button
  17. Return to the Water Distribution form and double-click the Close button
  18. Change the document as follows:
    namespace StellarWaterPoint3
    {
        public partial class WaterDistribution : Form
        {
            public WaterDistribution()
            {
                InitializeComponent();
            }
    
            private void WaterDistribution_Load(object sender, EventArgs e)
            {
                // If the directory for the database doesn't yet exist, create it
                Directory.CreateDirectory(@"C:\Stellar Water Point6");
            }
    
            private void btnCustomers_Click(object sender, EventArgs e)
            {
                Customers.Central central = new Customers.Central();
    
                central.ShowDialog();
            }
    
            private void btnWaterMeters_Click(object sender, EventArgs e)
            {
                WaterMeters.Central central = new WaterMeters.Central();
    
                central.ShowDialog();
            }
    
            private void btnWaterBills_Click(object sender, EventArgs e)
            {
                WaterBills.Central central = new();
    
                central.Show();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  19. To execute the application, on the main menu, click Debug -> Start Without Debugging:

    Stellar Water Point - New Customer Account

  20. On the Water Distribution form, click the Water Bills button:

    Stellar Water Point - Water Bills

  21. On the Water Bills form, click the Create Water Bill button:

    Stellar Water Point - Create Water Bill

  22. Enter the following values in the indicated text boxes or select the date values. Then click Find Customer Account, followed by Evaluate Water Bill, followed by Save Water Bill:

    Stellar Water Point - Create Water Bill

    Stellar Water Point - Create Water Bill

    Water Bill # Account # Reading Start Date Reading End Date Counter Reading Start Counter Reading End
    451474 2068-258-9486 01/11/2010 04/12/2010 103943 103956
    923633 5293-957-3395 01/17/2010 08/18/2010 256945 256972
    917829 9279-570-8394 02/15/2010 05/14/2010 5205 5222
    202666 6986-829-3741 03/08/2010 06/06/2010 5679 5690

    Stellar Water Point - Customers

  23. Close the forms and return to your programming environment

Details on a Wate Bill

.

Practical LearningPractical Learning: Creating a Water Meter Record

  1. To create a form, in the Solution Explorer, right-click WaterBills -> Add -> Form (Windows Forms)...
  2. For the Name of the form, type Details
  3. Press Enter
  4. Design the form as follows:

    Stellar Water Point - New Customer Account

    Control (Name) Text Other Properties
    Label Label   Water Bill #:  
    TextBox Text Box txtBillNumber    
    Button Button btnFindWaterBill Find Water Bill  
    GroupBox Label   Customer Information  
    Label Label   Account #:  
    TextBox Text Box txtAccountNumber   Enabled: False
    Label Label   Customer Name:  
    TextBox Text Box txtCustomerName   Enabled: False
    Label Label   Address:  
    TextBox Text Box txtAddress   Enabled: False
    TextBox Text Box txtCity   Enabled: False
    TextBox Text Box txtCounty   Enabled: False
    TextBox Text Box txtState   Enabled: False
    TextBox Text Box txtZIPCode   Enabled: False
    Label Label   _____________________________________  
    Label Label   Meter Details:  
    TextBox Text Box txtMeterDetails   Enabled: False
    GroupBox Label   Meter Reading  
    Label Label   Meter Reading Start Date:  
    TextBox Text Box txtMeterReadingStartDate   Enabled: False
    Label Label   Meter Reading End Date:  
    TextBox Text Box txtMeterReadingEndDate   Enabled: False
    Label Label   Counter Reading Start:  
    TextBox Text Box txtCounterReadingStart   Enabled: False
    Label Label   Counter Reading End:  
    TextBox Text Box txtCounterReadingEnd   Enabled: False
    GroupBox Label   Meter Result  
    Label Label   Billing Days:  
    TextBox Text Box txtBillingDays   TextAlign: Right
    Enabled: False
    Label Label   Total Gallons:  
    TextBox Text Box txtTotalGallons   TextAlign: Right
    Enabled: False
    Label Label   Total CCF:  
    TextBox Text Box txtTotalHCF   TextAlign: Right
    Enabled: False
    Label Label   First Tier Consumption:  
    TextBox Text Box txtFirstTierConsumption   TextAlign: Right
    Enabled: False
    Label Label   Second Tier:  
    TextBox Text Box txtSecondTierConsumption   TextAlign: Right
    Enabled: False
    Label Label   Last Tier:  
    TextBox Text Box txtLastTierConsumption   TextAlign: Right
    Enabled: False
    GroupBox Label   Consumption Charges  
    Label Label   Water Charges:  
    TextBox Text Box txtWaterCharges   TextAlign: Right
    Enabled: False
    Label Label   Sewer Charges:  
    TextBox Text Box txtSewerCharges   TextAlign: Right
    Enabled: False
    Label Label   Environment Charges:  
    TextBox Text Box txtEnvironmentCharges   TextAlign: Right
    Enabled: False
    Label Label   Total Charges:  
    TextBox Text Box txtTotalCharges   TextAlign: Right
    Enabled: False
    GroupBox Label   Taxes  
    Label Label   Local Taxes:  
    TextBox Text Box txtLocalTaxes   TextAlign: Right
    Enabled: False
    Label Label   State Taxes:  
    TextBox Text Box txtStateTaxes   TextAlign: Right
    Enabled: False
    GroupBox Label   Water Bill Payment  
    Label Label   Payment Due Date:  
    TextBox Text Box txtPaymentDueDate   Enabled: False
    Label Label   Amount Due:  
    TextBox Text Box txtAmountDue   TextAlign: Right
    Enabled: False
    Label Label   Late Payment Due Date:  
    TextBox Text Box txtLatePaymentDueDate   Enabled: False
    Label Label   Late Amount Due:  
    TextBox Text Box txtLateAmountDue   TextAlign: Right
    Enabled: False
    Button Button btnClose Close  
  5. Using the Properties window, change some characteristics of the form as follows:
    FormBorderStyle: FixedDialog
    Text:            Stellar Water Point - Water Bill Details
    StartPosition:   CenterScreen
    MinimizeBox:     False
    MaximizeBox:     False
  6. On the form, double-click the Find Water Bill button
  7. Return to the form and double-click the Close button
  8. Change the document as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.WaterBills
    {
        public partial class Details : Form
        {
            public Details()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterBill_Click(object sender, EventArgs e)
            {
                /* If the user clicks the Find Water Meter button, 
                 * make sure there is an invoice number in the top text box. */
                if (string.IsNullOrEmpty(txtBillNumber.Text))
                {
                    MessageBox.Show("You must provide a water bill number and then click the Find Water Bill button.",
                                    "Stellar Water Point", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    // If the user didn't type a bill number but clicked Find Water Bill, don't do anything
                    return;
                }
    
                XmlDocument xdWaterBills = new XmlDocument();
                string? strWaterBills = @"C:\Stellar Water Point6\WaterBills.xml";
    
                FileInfo? fiWaterBills = new FileInfo(strWaterBills);
    
                if (fiWaterBills.Exists)
                {
                    using (FileStream? fsWaterBills = new FileStream(fiWaterBills.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdWaterBills.Load(fsWaterBills);
    
                        /* Use XPath to locate the water bill that has 
                         * the same invoice number as the one in the Water Bill Number text box.
                         * Store the water bill in an XmlNodeList variable. */
                        XmlNodeList xnlWaterBills = xdWaterBills.DocumentElement!.SelectNodes("//bill-number[.='" + txtBillNumber.Text + "']")!;
    
                        foreach (XmlNode xnWaterBill in xnlWaterBills)
                        {
                            txtBillNumber.Text            =                xnWaterBill.FirstChild!.InnerText;
                            txtAccountNumber.Text         =                xnWaterBill.NextSibling!.InnerText;
                            txtMeterReadingStartDate.Text = DateTime.Parse(xnWaterBill.NextSibling.NextSibling!.InnerText).ToLongDateString();
                            txtMeterReadingEndDate.Text   = DateTime.Parse(xnWaterBill.NextSibling.NextSibling.NextSibling!.InnerText).ToLongDateString();                        
                            txtBillingDays.Text           =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText;
                            txtCounterReadingStart.Text   =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.InnerText;                        
                            txtCounterReadingEnd.Text     =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtTotalHCF.Text              =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtTotalGallons.Text          =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtFirstTierConsumption.Text  =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtSecondTierConsumption.Text =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtLastTierConsumption.Text   =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtWaterCharges.Text          =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtSewerCharges.Text          =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtEnvironmentCharges.Text    =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtServiceCharges.Text        =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtTotalCharges.Text          =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtStateTaxes.Text            =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtLocalTaxes.Text            =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtPaymentDueDate.Text        = DateTime.Parse(xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText).ToLongDateString();
                            txtAmountDue.Text             =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtLatePaymentDueDate.Text    = DateTime.Parse(xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText).ToLongDateString();
                            txtLateAmountDue.Text         =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                        }
                    }
                }
    
                XmlDocument xdCustomers = new XmlDocument();
                // Declare a variable for a file that holds the list of customers
                string? strCustomers = @"C:\Stellar Water Point6\Customers.xml";
    
                // Create a FileInfo object for the customers
                FileInfo? fiCustomers = new FileInfo(strCustomers);
    
                // We will need to know the water meter associated with this customer account
                string strMeterNumber = string.Empty;
    
                // Check whether the file that holds a list of customers exists
                if (fiCustomers.Exists)
                {
                    // If that exists, open it and pass it to a FileStream object
                    using (FileStream? fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        // Get the list of customers and pass the records to the XML DOM object created earlier
                        xdCustomers.Load(fsCustomers);
                        // Create an XmlNodeList list of customers using XPath
                        XmlNodeList xnlCustomers = xdCustomers.DocumentElement!.SelectNodes("//account-number[.='" + txtAccountNumber.Text + "']")!;
    
                        // Check each node of the XML record and display its values in each Windows control on the form
                        foreach (XmlNode xnCustomer in xnlCustomers)
                        {
                            //mtbAccountNumber.Text = xnCustomer.NextSibling!.InnerText;   // Meter #
                            txtAccountName.Text = xnCustomer.NextSibling!.InnerText; // Account Name
    
                            strMeterNumber      = xnCustomer.NextSibling.NextSibling!.InnerText;   // Meter Number
                            txtAccountType.Text = xnCustomer.NextSibling.NextSibling.NextSibling!.InnerText;   // Account Type
                            txtAddress.Text     = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText;   // Address
                            txtCity.Text        = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText;   // City
                            txtCounty.Text      = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.InnerText;   // County
                            txtState.Text       = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;   // State
                            txtZIPCode.Text     = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText; // ZIP-Code
                        }
                    }
                }
    
                // Create an XML DOM object for the water meters records
                XmlDocument xdWaterMeters = new XmlDocument();
                // Declare a variable for a file that holds the list of water meters
                string? strWaterMeters = @"C:\Stellar Water Point6\WaterMeters.xml";
    
                // Create a FileInfo object for the customers
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                // Check whether the file that holds a list of water meters exists
                if (fiWaterMeters.Exists)
                {
                    // Get the list of water meters and pass the records to the XML DOM object
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        // Get the list of water meters and pass the records to the XML DOM object
                        xdWaterMeters.Load(fsWaterMeters);
                        // Create an XmlNodeList list of water meters using XPath
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + strMeterNumber + "']")!;
    
                        // Check each node of the XML record
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            /* Get the values for the water meter.
                             * Create a sentence and display it in the Meter Details text box. */
                            txtMeterDetails.Text = xnWaterMeter.NextSibling!.InnerText + " " +
                                                   xnWaterMeter.NextSibling.NextSibling!.InnerText + " (Meter Size: " +
                                                   xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText + ")";
                        }
                    }
                }
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  9. In the Solution Explorer, below the WaterBills folder, double-click Details.cs to open its form
  10. From the Toolbox, add a button to the form below the list view and to the right of the Create Water Bill button
  11. Change the characteristics of the button as follows:

    Stellar Water Point - Water Bills

    Control (Name) Other Properties
    Button Button btnViewWaterBill &View Water Bill...
    Anchor: Bottom, Right
  12. Double-click the View Water Bill button
  13. Change the document as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.WaterBills
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowWaterBills()
            {
                . . .
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                ShowWaterBills();
            }
    
            private void btnCreateWaterBill_Click(object sender, EventArgs e)
            {
                Create create = new();
    
                create.ShowDialog();
    
                ShowWaterBills();
            }
    
            private void btnViewWaterBill_Click(object sender, EventArgs e)
            {
                Details details = new();
    
                details.ShowDialog();
            }
        }
    }
  14. To execute the application, on the main menu, click Debug -> Start Without Debugging

    Stellar Water Point

  15. On the Water Distribution form, click the Water Bills button:

    Stellar Water Point - Customers

  16. On the Water Bills form, click the View Water Bill button:

    Stellar Water Point - View Water Bill

  17. In the Water Bill # text box, type 917829

    Stellar Water Point - View Water Bill

  18. Click the Find Water Bill button:

    Stellar Water Point - View Water Bill

  19. Close the Details form
  20. Close the forms and return to your programming environment

Water Bill Edition

.

Practical LearningPractical Learning: Editing a Water Bill

  1. To create a new form, in the Solution Explorer, right-click Water Bills -> New -> Form (Windows Forms)...
  2. Type Editor as the name of the form
  3. Click Add
  4. Make that form the same size as the Create Water Bill form
  5. Select everything on the Create Water Bill form. Copy that selection and paste it in the new Water Bill Editor form
  6. Copy the Find Water Bill button from the Water Bill Details form and paste it on the Water Bill Editor form
  7. Complete the design of the form as follows:

    Stellar Water Point - Water Bill Editor

    Control (Name) Text Other Properties
    Label Label   Water Bill #:  
    TextBox Text Box txtBillNumber   Modifiers: Public
    Button Button btnFindWaterBill &Find Water Bill  
    GroupBox Label   Customer Information  
    Label Label   Account #:  
    MaskedTextBox Masked Text Box mtbAccountNumber   Masked: 0000-000-0000
    Modifiers: Public
    Button Button btnFindCustomerAccount Find Customer Account  
    Label Label   Account Name:  
    TextBox Text Box txtAccountName   Enabled: False
    Label Label   Address:  
    TextBox Text Box txtAddress   Enabled: False
    TextBox Text Box txtCity   Enabled: False
    TextBox Text Box txtCounty   Enabled: False
    TextBox Text Box txtState   Enabled: False
    TextBox Text Box mtbZIPCode   Enabled: False
    Label Label   ______________________________________________  
    Label Label   Meter Details:  
    TextBox Text Box txtMeterDetails   Modifiers: Public
    GroupBox Label   Meter Reading  
    Label Label   Meter Reading Start Date:  
    DateTimePicker Date Time Picker dtpMeterReadingStartDate   Modifiers: Public
    Label Label   Meter Reading End Date:  
    DateTimePicker Date Time Picker dtpMeterReadingEndDate   Modifiers: Public
    Label Label   Counter Reading Start:  
    TextBox Text Box txtCounterReadingStart   Modifiers: Public
    Label Label   Counter Reading End:  
    TextBox Text Box txtCounterReadingEnd   Modifiers: Public
    Button Button btnEvaluateWaterBill Evaluate Water Bill  
    GroupBox Label   Meter Result  
    Label Label   Billing Days:  
    TextBox Text Box txtBillingDays   TextAlign: Right
    Modifiers: Public
    Label Label   Total Gallons:  
    TextBox Text Box txtTotalGallons   TextAlign: Right
    Modifiers: Public
    Label Label   Total CCF:  
    TextBox Text Box txtTotalCCF   TextAlign: Right
    Modifiers: Public
    Label Label   First Tier Consumption:  
    TextBox Text Box txtFirstTierConsumption   TextAlign: Right
    Modifiers: Public
    Label Label   Second Tier:  
    TextBox Text Box txtSecondTierConsumption   TextAlign: Right
    Modifiers: Public
    Label Label   Last Tier:  
    TextBox Text Box txtLastTierConsumption   TextAlign: Right
    Modifiers: Public
    GroupBox Label   Consumption Charges  
    Label Label   Water Charges:  
    TextBox Text Box txtWaterCharges   TextAlign: Right
    Modifiers: Public
    Label Label   Sewer Charges:  
    TextBox Text Box txtSewerCharges   TextAlign: Right
    Modifiers: Public
    Label Label   Environment Charges:  
    TextBox Text Box txtEnvironmentCharges   TextAlign: Right
    Modifiers: Public
    Label Label   Total Charges:  
    TextBox Text Box txtTotalCharges   TextAlign: Right
    Modifiers: Public
    GroupBox Label   Taxes  
    Label Label   Local Taxes:  
    TextBox Text Box txtLocalTaxes   TextAlign: Right
    Modifiers: Public
    Label Label   State Taxes:  
    TextBox Text Box txtStateTaxes   TextAlign: Right
    Modifiers: Public
    GroupBox Label   Water Bill Payment  
    Label Label   Payment Due Date:  
    DateTimePicker Date Time Picker dtpPaymentDueDate   Modifiers: Public
    Label Label   Amount Due:  
    TextBox Text Box txtAmountDue   TextAlign: Right
    Modifiers: Public
    Label Label   Late Payment Due Date:  
    DateTimePicker Date Time Picker dtpLatePaymentDueDate   Modifiers: Public
    Label Label   Late Amount Due:  
    TextBox Text Box txtLateAmountDue   TextAlign: Right
    Modifiers: Public
    Button Button btnUpdateWaterBill Update Water Bill DialogResult: OK
    Button Button btnClose Close DialogResult: Cancel
  8. Using the Properties window, change some characteristics of the form as follows:
    FormBorderStyle: FixedDialog
    Text:            Stellar Water Point - Water Bill Edition
    StartPosition:   CenterScreen
    MinimizeBox:     False
    MaximizeBox:     False
    AcceptButton:    btnUpdateWaterBill
    CancelButton:    btnClose
  9. On the form, double-click the Find Water Bill button
  10. Change the document as follows:
    using System.Xml;using System.Xml;
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterBill_Click(object sender, EventArgs e)
            {
                if (string.IsNullOrEmpty(txtBillNumber.Text))
                {
                    MessageBox.Show("You must provide a water bill number and then click the Find Water Bill button.",
                                    "Stellar Water Point", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }
    
                XmlDocument xdWaterBills = new XmlDocument();
                string? strWaterBills = @"C:\Stellar Water Point6\WaterBills.xml";
    
                FileInfo? fiWaterBills = new FileInfo(strWaterBills);
    
                if (fiWaterBills.Exists)
                {
                    using (FileStream? fsWaterBills = new FileStream(fiWaterBills.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdWaterBills.Load(fsWaterBills);
    
                        XmlNodeList xnlWaterBills = xdWaterBills.DocumentElement!.SelectNodes("//bill-number[.='" + txtBillNumber.Text + "']")!;
    
                        foreach (XmlNode xnWaterBill in xnlWaterBills)
                        {
                            txtBillNumber.Text            =                xnWaterBill.FirstChild!.InnerText;
                            mtbAccountNumber.Text         =                xnWaterBill.NextSibling!.InnerText;
                            dtpMeterReadingStartDate.Text = DateTime.Parse(xnWaterBill.NextSibling.NextSibling!.InnerText).ToLongDateString();
                            dtpMeterReadingEndDate.Text   = DateTime.Parse(xnWaterBill.NextSibling.NextSibling.NextSibling!.InnerText).ToLongDateString();
                            txtBillingDays.Text           =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText;
                            txtCounterReadingStart.Text   =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.InnerText;
                            txtCounterReadingEnd.Text     =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtTotalHCF.Text              =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtTotalGallons.Text          =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtFirstTierConsumption.Text  =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtSecondTierConsumption.Text =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtLastTierConsumption.Text   =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtWaterCharges.Text          =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtSewerCharges.Text          =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtEnvironmentCharges.Text    =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtServiceCharges.Text        =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtTotalCharges.Text          =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtStateTaxes.Text            =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtLocalTaxes.Text            =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            dtpPaymentDueDate.Text        = DateTime.Parse(xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText).ToLongDateString();
                            txtAmountDue.Text             =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            dtpLatePaymentDueDate.Text    = DateTime.Parse(xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText).ToLongDateString();
                            txtLateAmountDue.Text         =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                        }
                    }
                }
    
                XmlDocument xdCustomers = new XmlDocument();
                string? strCustomers = @"C:\Stellar Water Point6\Customers.xml";
    
                FileInfo? fiCustomers = new FileInfo(strCustomers);
    
                string strMeterNumber = string.Empty;
    
                if (fiCustomers.Exists)
                {
                    using (FileStream? fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdCustomers.Load(fsCustomers);
                        XmlNodeList xnlCustomers = xdCustomers.DocumentElement!.SelectNodes("//account-number[.='" + mtbAccountNumber.Text + "']")!;
    
                        foreach (XmlNode xnCustomer in xnlCustomers)
                        {
                            txtAccountName.Text = xnCustomer.NextSibling!.InnerText; // Account Name
    
                            strMeterNumber = xnCustomer.NextSibling.NextSibling!.InnerText;   // Meter Number
                            txtAccountType.Text = xnCustomer.NextSibling.NextSibling.NextSibling!.InnerText;   // Account Type
                            txtAddress.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText;   // Address
                            txtCity.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText;   // City
                            txtCounty.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.InnerText;   // County
                            txtState.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;   // State
                            txtZIPCode.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText; // ZIP-Code
                        }
                    }
                }
    
                XmlDocument xdWaterMeters = new XmlDocument();
                string? strWaterMeters = @"C:\Stellar Water Point6\WaterMeters.xml";
    
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                if (fiWaterMeters.Exists)
                {
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdWaterMeters.Load(fsWaterMeters);
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + strMeterNumber + "']")!;
    
                        // Check each node of the XML record
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            txtMeterDetails.Text = xnWaterMeter.NextSibling!.InnerText + " " +
                                                   xnWaterMeter.NextSibling.NextSibling!.InnerText + " (Meter Size: " +
                                                   xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText + ")";
                        }
                    }
                }
            }
        }
    }
  11. Return to the Water Bill - Editor form and double-click the Find Customer Account button
  12. Implement the event as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.WaterBills
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterBill_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                XmlDocument xdCustomers = new XmlDocument();
                string? strCustomers = @"C:\Stellar Water Point6\Customers.xml";
    
                FileInfo? fiCustomers = new FileInfo(strCustomers);
    
                string strMeterNumber = string.Empty;
    
                if (fiCustomers.Exists)
                {
                    using (FileStream? fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdCustomers.Load(fsCustomers);
                        XmlNodeList xnlCustomers   = xdCustomers.DocumentElement!.SelectNodes("//account-number[.='" + mtbAccountNumber.Text + "']")!;
    
                        foreach (XmlNode xnCustomer in xnlCustomers)
                        {
                            txtAccountName.Text    = xnCustomer.NextSibling!.InnerText;
                            strMeterNumber         = xnCustomer.NextSibling.NextSibling!.InnerText;
                            txtAccountType.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;
                        }
                    }
                }
    
                XmlDocument xdWaterMeters = new XmlDocument();
                string? strWaterMeters = @"C:\Stellar Water Point6\WaterMeters.xml";
    
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                if (fiWaterMeters.Exists)
                {
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdWaterMeters.Load(fsWaterMeters);
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + strMeterNumber + "']")!;
    
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            txtMeterDetails.Text = xnWaterMeter.NextSibling!.InnerText + " " +
                                                   xnWaterMeter.NextSibling.NextSibling!.InnerText + " (Meter Size: " +
                                                   xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText + ")";
                        }
                    }
                }
            }
        }
    }
  13. Return to the Water Bill - Editor form and double-click the Meter Reading End Date date time picker
  14. Implement the event as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.WaterBills
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterBill_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void dtpMeterReadingEndDate_ValueChanged(object sender, EventArgs e)
            {
                TimeSpan tsDays = dtpMeterReadingEndDate.Value - dtpMeterReadingStartDate.Value;
    
                txtBillingDays.Text = (tsDays.Days + 1).ToString();
            }
        }
    }
  15. Return to the Water Bill - Editor form and double-click the Re-Evaluate Water Bill button
  16. Implement the event as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.WaterBills
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterBill_Click(object sender, EventArgs e)
            {
                if (string.IsNullOrEmpty(txtBillNumber.Text))
                {
                    MessageBox.Show("You must provide a water bill number and then click the Find Water Bill button.",
                                    "Stellar Water Point", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }
    
                XmlDocument xdWaterBills = new XmlDocument();
                string? strWaterBills = @"C:\Stellar Water Point6\WaterBills.xml";
    
                FileInfo? fiWaterBills = new FileInfo(strWaterBills);
    
                if (fiWaterBills.Exists)
                {
                    using (FileStream? fsWaterBills = new FileStream(fiWaterBills.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdWaterBills.Load(fsWaterBills);
    
                        XmlNodeList xnlWaterBills = xdWaterBills.DocumentElement!.SelectNodes("//bill-number[.='" + txtBillNumber.Text + "']")!;
    
                        foreach (XmlNode xnWaterBill in xnlWaterBills)
                        {
                            txtBillNumber.Text            =                xnWaterBill.FirstChild!.InnerText;
                            mtbAccountNumber.Text         =                xnWaterBill.NextSibling!.InnerText;
                            dtpMeterReadingStartDate.Text = DateTime.Parse(xnWaterBill.NextSibling.NextSibling!.InnerText).ToLongDateString();
                            dtpMeterReadingEndDate.Text   = DateTime.Parse(xnWaterBill.NextSibling.NextSibling.NextSibling!.InnerText).ToLongDateString();
                            txtBillingDays.Text           =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText;
                            txtCounterReadingStart.Text   =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.InnerText;
                            txtCounterReadingEnd.Text     =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtTotalHCF.Text              =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtTotalGallons.Text          =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtFirstTierConsumption.Text  =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtSecondTierConsumption.Text =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtLastTierConsumption.Text   =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtWaterCharges.Text          =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtSewerCharges.Text          =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtEnvironmentCharges.Text    =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtServiceCharges.Text        =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtTotalCharges.Text          =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtStateTaxes.Text            =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtLocalTaxes.Text            =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            dtpPaymentDueDate.Text        = DateTime.Parse(xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText).ToLongDateString();
                            txtAmountDue.Text             =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            dtpLatePaymentDueDate.Text    = DateTime.Parse(xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText).ToLongDateString();
                            txtLateAmountDue.Text         =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                        }
                    }
                }
    
                XmlDocument xdCustomers = new XmlDocument();
                string? strCustomers = @"C:\Stellar Water Point6\Customers.xml";
    
                FileInfo? fiCustomers = new FileInfo(strCustomers);
    
                string strMeterNumber = string.Empty;
    
                if (fiCustomers.Exists)
                {
                    using (FileStream? fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdCustomers.Load(fsCustomers);
                        XmlNodeList xnlCustomers = xdCustomers.DocumentElement!.SelectNodes("//account-number[.='" + mtbAccountNumber.Text + "']")!;
    
                        foreach (XmlNode xnCustomer in xnlCustomers)
                        {
                            txtAccountName.Text = xnCustomer.NextSibling!.InnerText; // Account Name
    
                            strMeterNumber = xnCustomer.NextSibling.NextSibling!.InnerText;   // Meter Number
                            txtAccountType.Text = xnCustomer.NextSibling.NextSibling.NextSibling!.InnerText;   // Account Type
                            txtAddress.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText;   // Address
                            txtCity.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText;   // City
                            txtCounty.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.InnerText;   // County
                            txtState.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;   // State
                            txtZIPCode.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText; // ZIP-Code
                        }
                    }
                }
    
                XmlDocument xdWaterMeters = new XmlDocument();
                string? strWaterMeters = @"C:\Stellar Water Point6\WaterMeters.xml";
    
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                if (fiWaterMeters.Exists)
                {
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdWaterMeters.Load(fsWaterMeters);
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + strMeterNumber + "']")!;
    
                        // Check each node of the XML record
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            txtMeterDetails.Text = xnWaterMeter.NextSibling!.InnerText + " " +
                                                   xnWaterMeter.NextSibling.NextSibling!.InnerText + " (Meter Size: " +
                                                   xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText + ")";
                        }
                    }
                }
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                XmlDocument xdCustomers = new XmlDocument();
                string? strCustomers = @"C:\Stellar Water Point6\Customers.xml";
    
                FileInfo? fiCustomers = new FileInfo(strCustomers);
    
                string strMeterNumber = string.Empty;
    
                if (fiCustomers.Exists)
                {
                    using (FileStream? fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdCustomers.Load(fsCustomers);
                        XmlNodeList xnlCustomers = xdCustomers.DocumentElement!.SelectNodes("//account-number[.='" + mtbAccountNumber.Text + "']")!;
    
                        foreach (XmlNode xnCustomer in xnlCustomers)
                        {
                            txtAccountName.Text = xnCustomer.NextSibling!.InnerText;
                            strMeterNumber = xnCustomer.NextSibling.NextSibling!.InnerText;
                            txtAccountType.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;
                        }
                    }
                }
    
                XmlDocument xdWaterMeters = new XmlDocument();
                string? strWaterMeters = @"C:\Stellar Water Point6\WaterMeters.xml";
    
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                if (fiWaterMeters.Exists)
                {
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdWaterMeters.Load(fsWaterMeters);
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + strMeterNumber + "']")!;
    
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            txtMeterDetails.Text = xnWaterMeter.NextSibling!.InnerText + " " +
                                                   xnWaterMeter.NextSibling.NextSibling!.InnerText + " (Meter Size: " +
                                                   xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText + ")";
                        }
                    }
                }
            }
    
            private void dtpMeterReadingEndDate_ValueChanged(object sender, EventArgs e)
            {
                TimeSpan tsDays = dtpMeterReadingEndDate.Value - dtpMeterReadingStartDate.Value;
    
                txtBillingDays.Text = (tsDays.Days + 1).ToString();
            }
    
            (double a, double b, double c) CalculateTiers(string acnt, double total)
            {
                (double tier1, double tier2, double tier3) results = (0.00, 0.00, 0.00);
    
                if (acnt == "RES")
                {
                    results.tier1 = total * 41.50 / 10000.00;
                    results.tier2 = total * 32.50 / 10000.00;
                    results.tier3 = total * 26.00 / 10000.00;
                }
                else if (acnt == "SGO")
                {
                    results.tier1 = total * 46 / 10000;
                    results.tier2 = total * 50 / 10000;
                    results.tier3 = total *  4 / 10000;
                }
                else if (acnt == "BUS")
                {
                    results.tier1 = total * 45 / 10000;
                    results.tier2 = total * 30 / 10000;
                    results.tier3 = total * 25 / 10000;
                }
                else if (acnt == "UUO")
                {
                    results.tier1 = total * 25 / 10000;
                    results.tier2 = total * 35 / 10000;
                    results.tier3 = total * 40 / 10000;
                }
                else if (acnt == "WAT")
                {
                    results.tier1 = total * 50 / 10000;
                    results.tier2 = total * 40 / 10000;
                    results.tier3 = total * 10 / 10000;
                }
                else if (acnt == "OTH")
                {
                    results.tier1 = total * (48.00 / 10000.00);
                    results.tier2 = total * (32.00 / 10000.00);
                    results.tier3 = total * (20.00 / 10000.00);
                }
    
                return results;
            }
    
            private double CalculateSewerCharges(string acnt, double total)
            {
                double result;
    
                if (acnt == "RES")
                {
                    result = total * 6.826941 / 100;
                }
                else if (acnt == "SGO")
                {
                    result = total * 4.162522 / 100;
                }
                else if (acnt == "BUS")
                {
                    result = total * 8.3136 / 100;
                }
                else if (acnt == "UUO")
                {
                    result = total * 10.6247 / 100;
                }
                else if (acnt == "WAT")
                {
                    result = total * 12.0535 / 100;
                }
                else // OTH
                {
                    result = total * 9.2065 / 100;
                }
    
                return result;
            }
    
            private double CalculateEnvironmentCharges(string acnt, double total)
            {
                double result;
    
                switch (acnt)
                {
                    case "RES":
                        result = total * 0.022724;
                        break;
                    case "SGO":
                        result = total * 0.118242;
                        break;
                    case "BUS":
                        result = total * 0.161369;
                        break;
                    case "UUO":
                        result = total * 0.082477;
                        break;
                    case "WAT":
                        result = total * 0.413574;
                        break;
                    default:
                        result = total * 0.22184;
                        break;
                }
    
                return result;
            }
    
            private double CalculateServiceCharges(string acnt, double total)
            {
                if (acnt == "RES")
                {
                    return total * 0.145748;
                }
                else if (acnt == "SGO")
                {
                    return total * 0.10224;
                }
                else if (acnt == "BUS")
                {
                    return total * 0.242627;
                }
                else if (acnt == "UUO")
                {
                    return total * 0.18669;
                }
                else if (acnt == "WAT")
                {
                    return total * 0.412628;
                }
                else
                {
                    return total * 0.210248;
                }
            }
    
            private double CalculateLocalTaxes(string acnt, double total) => acnt switch
            {
                "RES" => total * 0.031574,
                "SGO" => total * 0.035026,
                "BUS" => total * 0.122517,
                "UUO" => total * 0.105737,
                "WAT" => total * 0.153248,
                _ => total * 0.125148
            };
    
            private double CalculateStateTaxes(string acnt, double total) => acnt switch
            {
                "RES" => total * 0.016724,
                "SGO" => total * 0.008779,
                "BUS" => total * 0.042448,
                "UUO" => total * 0.067958,
                "WAT" => total * 0.081622,
                _ => total * 0.013746
            };
    
            private DateTime SetPaymentDueDate(string acnt, DateTime date)
            {
                TimeSpan tsPaymentDueDate = new TimeSpan(1, 0, 0, 0);
    
                if (acnt == "RES")
                {
                    tsPaymentDueDate = new TimeSpan(15, 0, 0, 0);
                }
                else if (acnt == "SGO")
                {
                    tsPaymentDueDate = new TimeSpan(20, 0, 0, 0);
                }
                else if (acnt == "BUS")
                {
                    tsPaymentDueDate = new TimeSpan(30, 0, 0, 0);
                }
                else if (acnt == "UUO")
                {
                    tsPaymentDueDate = new TimeSpan(15, 0, 0, 0);
                }
                else if (acnt == "WAT")
                {
                    tsPaymentDueDate = new TimeSpan(40, 0, 0, 0);
                }
                else
                {
                    tsPaymentDueDate = new TimeSpan(35, 0, 0, 0);
                }
    
                return date + tsPaymentDueDate;
            }
    
            private DateTime SetLatePaymentDueDate(string acnt, DateTime date)
            {
                TimeSpan tsLatePaymentDueDate = new TimeSpan(1, 0, 0, 0);
    
                if (acnt == "RES")
                {
                    tsLatePaymentDueDate = new TimeSpan(30, 0, 0, 0);
    
                    return date + tsLatePaymentDueDate;
                }
                else if (acnt == "SGO")
                {
                    tsLatePaymentDueDate = new TimeSpan(40, 0, 0, 0);
    
                    return date + tsLatePaymentDueDate;
                }
                else if (acnt == "BUS")
                {
                    tsLatePaymentDueDate = new TimeSpan(50, 0, 0, 0);
    
                    return date + tsLatePaymentDueDate;
                }
                else if (acnt == "UUO")
                {
                    tsLatePaymentDueDate = new TimeSpan(60, 0, 0, 0);
    
                    return date + tsLatePaymentDueDate;
                }
                else if (acnt == "WAT")
                {
                    tsLatePaymentDueDate = new TimeSpan(65, 0, 0, 0);
    
                    return date + tsLatePaymentDueDate;
                }
                else
                {
                    tsLatePaymentDueDate = new TimeSpan(45, 0, 0, 0);
    
                    return date + tsLatePaymentDueDate;
                }
            }
    
            private double CalculateLateAmountDue(string acnt, double amt)
            {
                double result;
    
                if (acnt == "RES")
                {
                    result = amt + 8.95;
                }
                else if (acnt == "SGO")
                {
                    result = amt + (amt / 4.575);
                }
                else if (acnt == "BUS")
                {
                    result = amt + (amt / 12.315);
                }
                else if (acnt == "UUO")
                {
                    result = amt + (amt / 7.425);
                }
                else if (acnt == "WAT")
                {
                    result = amt + (amt / 15.225);
                }
                else
                {
                    result = amt + (amt / 6.735);
                }
    
                return result;
            }
    
            private void btnEvaluateWaterBill_Click(object sender, EventArgs e)
            {
                double counterStart = 0, counterEnd = 0;
    
                try
                {
                    counterStart = double.Parse(txtCounterReadingStart.Text);
                }
                catch (FormatException feCRStart)
                {
                    MessageBox.Show("There was a problem with the value of the " +
                                    "Counter Reading Start. The error produced is: " + feCRStart.Message,
                                    "Stellar Water Point", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
    
                try
                {
                    counterEnd = double.Parse(txtCounterReadingEnd.Text);
                }
                catch (FormatException feCREnd)
                {
                    MessageBox.Show("There was a problem with the value of the " +
                                    "Counter Reading End. The error produced is: " + feCREnd.Message,
                                    "Stellar Water Point", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
    
                double consumption = counterEnd - counterStart;
                double gallons = consumption * 748.05;
    
                string strAccountType = txtAccountType.Text[..3];
    
                (double first, double second, double last) tiers = CalculateTiers(strAccountType, gallons);
    
                double waterCharges = tiers.first + tiers.second + tiers.last;
                double sewerCharges = CalculateSewerCharges(strAccountType, waterCharges);
                double envCharges = CalculateEnvironmentCharges(strAccountType, waterCharges);
                double srvCharges = CalculateServiceCharges(strAccountType, waterCharges);
                double totalCharges = waterCharges + sewerCharges + envCharges + srvCharges;
                double localTaxes = CalculateLocalTaxes(strAccountType, waterCharges);
                double stateTaxes = CalculateStateTaxes(strAccountType, waterCharges);
                double amtDue = totalCharges + localTaxes + stateTaxes;
    
                txtTotalHCF.Text = consumption.ToString();
                txtTotalGallons.Text = gallons.ToString("F");
                txtFirstTierConsumption.Text = tiers.first.ToString("F");
                txtSecondTierConsumption.Text = tiers.second.ToString("F");
                txtLastTierConsumption.Text = tiers.last.ToString("F");
                txtWaterCharges.Text = waterCharges.ToString("F");
                txtSewerCharges.Text = sewerCharges.ToString("F");
                txtEnvironmentCharges.Text = envCharges.ToString("F");
                txtServiceCharges.Text = srvCharges.ToString("F");
                txtTotalCharges.Text = totalCharges.ToString("F");
                txtLocalTaxes.Text = localTaxes.ToString("F");
                txtStateTaxes.Text = stateTaxes.ToString("F");
                dtpPaymentDueDate.Value = SetPaymentDueDate(strAccountType, dtpMeterReadingEndDate.Value);
                txtAmountDue.Text = amtDue.ToString("F");
                dtpLatePaymentDueDate.Value = SetLatePaymentDueDate(strAccountType, dtpMeterReadingEndDate.Value);
                txtLateAmountDue.Text = CalculateLateAmountDue(strAccountType, amtDue).ToString("F");
            }
        }
    }
  17. In the Solution Explorer, below the WaterBills folder, double-click Central.cs
  18. From the Toolbox, add a button to the form below the list view and on the right side of the View Water Bill button
  19. Change the characteristics of the button as follows:

    Stellar Water Point - Water Meters

    Control (Name) Text Other Properties
    ListView List View lvwWaterBills   No Change
    Button Button btnNewWaterBill   No Change
    Button Button btnViewWaterBill   No Change
    Button Button btnEditWaterBill &Edit Water Bill... Anchor: Bottom, Right
  20. Double-click the Edit Water Bill button
  21. Implement the event as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.WaterBills
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowWaterBills()
            {
                . . .
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                ShowWaterBills();
            }
    
            private void btnCreateWaterBill_Click(object sender, EventArgs e)
            {
                Create create = new();
    
                create.ShowDialog();
    
                ShowWaterBills();
            }
    
            private void btnViewWaterBill_Click(object sender, EventArgs e)
            {
                Details details = new();
    
                details.ShowDialog();
            }
    
            private void btnEditWaterBill_Click(object sender, EventArgs e)
            {
                Editor editor = new();
    
                if (editor.ShowDialog() == DialogResult.OK)
                {
                    if (string.IsNullOrEmpty(editor.txtBillNumber.Text))
                    {
                        MessageBox.Show("You must first type a bill number and then click the Find Water Bill button. " +
                                        "You can then optionally change some values on the water bill and save it.",
                                        "Stellar Water Point", MessageBoxButtons.OK);
                        return;
                    }
    
                    XmlDocument xdWaterBills = new XmlDocument();
                    string? strWaterBills    = @"C:\Stellar Water Point6\WaterBills.xml";
    
                    xdWaterBills.Load(strWaterBills);
    
                    XmlNodeList xnlWaterBills = xdWaterBills.DocumentElement!.GetElementsByTagName("bill-number");
    
                    foreach (XmlNode xnWaterBill in xnlWaterBills)
                    {
                        if (xnWaterBill.InnerText.Contains(editor.txtBillNumber.Text))
                        {
                            xnWaterBill.ParentNode!.InnerXml =
                                "<bill-number>"              + editor.txtBillNumber.Text + "</bill-number>" +
                                "<account-number>"           + editor.mtbAccountNumber.Text + "</account-number>" +
                                "<meter-reading-start-date>" + editor.dtpMeterReadingStartDate.Value.ToShortDateString() + "</meter-reading-start-date>" +
                                "<meter-reading-end-date>"   + editor.dtpMeterReadingEndDate.Value.ToShortDateString() + "</meter-reading-end-date>" +
                                "<billing-days>"             + editor.txtBillingDays.Text + "</billing-days>" +
                                "<counter-reading-start>"    + editor.txtCounterReadingStart.Text + "</counter-reading-start>" +
                                "<counter-reading-end>"      + editor.txtCounterReadingEnd.Text + "</counter-reading-end>" +
                                "<total-hcf>"                + editor.txtTotalHCF.Text + "</total-hcf>" +
                                "<total-gallons>"            + editor.txtTotalGallons.Text + "</total-gallons>" +
                                "<first-tier-consumption>"   + editor.txtFirstTierConsumption.Text + "</first-tier-consumption>" +
                                "<second-tier-consumption>"  + editor.txtSecondTierConsumption.Text + "</second-tier-consumption>" +
                                "<last-tier-consumption>"    + editor.txtLastTierConsumption.Text + "</last-tier-consumption>" +
                                "<water-charges>"            + editor.txtWaterCharges.Text + "</water-charges>" +
                                "<sewer-charges>"            + editor.txtSewerCharges.Text + "</sewer-charges>" +
                                "<environment-charges>"      + editor.txtEnvironmentCharges.Text + "</environment-charges>" +
                                "<service-charges>"          + editor.txtEnvironmentCharges.Text + "</service-charges>" +
                                "<total-charges>"            + editor.txtTotalCharges.Text + "</total-charges>" +
                                "<state-taxes>"              + editor.txtStateTaxes.Text + "</state-taxes>" +
                                "<local-taxes>"              + editor.txtLocalTaxes.Text + "</local-taxes>" +
                                "<payment-due-date>"         + editor.dtpPaymentDueDate.Value.ToShortDateString() + "</payment-due-date>" +
                                "<amount-due>"               + editor.txtAmountDue.Text + "</amount-due>" +
                                "<late-payment-due-date>"    + editor.dtpLatePaymentDueDate.Value.ToShortDateString() + "</late-payment-due-date>" +
                                "<late-amount-due>"          + editor.txtLateAmountDue.Text + "</late-amount-due>";
    
                            xdWaterBills.Save(strWaterBills);
                            break;
                        }
                    }
                }
                
                ShowWaterBills();
            }
        }
    }
  22. To execute the application, on the main menu, click Debug -> Start Without Debugging

    Stellar Water Point

  23. On the main form of the application, click the Customers button:

    Stellar Water Point - Water Bills

  24. Click the Edit Water Bill button:

    Stellar Water Point - Water Bill Editor

  25. In the Water Bill # text, type 923633
  26. Click the Find Water Bill button

    Stellar Water Point - Water Bill Editor

  27. Change the following values:
    Account #:                9249-379-6848 and click Find Customer Account
    Meter Reading Start Date: 1/19/2010
    Meter Reading End Date:   4/17/2010
    Counter Reading Start:    256953
    Counter Reading End:      256966
  28. Click the Re-Evaluate Water Bill button:

    Stellar Water Point - New Water Bill

  29. Click the Update Water Bill button:

    Stellar Water Point - Water Bills

  30. Close the forms and return to your programming environment

Deleting a Water Bill

.

Practical LearningPractical Learning: Deleting a Customer Account

  1. To create a new form, in the Solution Explorer, right-click Water Bills -> New -> Form (Windows Forms)...
  2. Set the name of the file and form to Delete
  3. Click Add
  4. Make that form the same size as the Water Bill - Details form
  5. Select everything on the Water Bill - Details form and copy that selection
  6. Paste that selection in the Water Bill - Delete form
  7. Complete the design of the form as follows:

    Stellar Water Point - Water Bill Deletion

    Control (Name) Text
    Button Button btnDeleteWaterBill &Delete Water Bill
  8. Using the Properties window, change some characteristics of the form as follows:
    FormBorderStyle: FixedDialog
    Text:            Stellar Water Point - Water Bill Deletion
    StartPosition:   CenterScreen
    MinimizeBox:     False
    MaximizeBox:     False
    ShowInTaskbar:   False
  9. On the form, double-click the Find Water Bill button
  10. Change the document as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.WaterBills
    {
        public partial class Delete : Form
        {
            public Delete()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterBill_Click(object sender, EventArgs e)
            {
                /* If the user clicks the Find Water Meter button, 
                 * make sure there is an invoice number in the top text box. */
                if (string.IsNullOrEmpty(txtBillNumber.Text))
                {
                    MessageBox.Show("You must provide a water bill number and then click the Find Water Bill button.",
                                    "Stellar Water Point", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    // If the user didn't type a bill number but clicked Find Water Bill, don't do anything
                    return;
                }
    
                XmlDocument xdWaterBills = new XmlDocument();
                string? strWaterBills = @"C:\Stellar Water Point6\WaterBills.xml";
    
                FileInfo? fiWaterBills = new FileInfo(strWaterBills);
    
                if (fiWaterBills.Exists)
                {
                    using (FileStream? fsWaterBills = new FileStream(fiWaterBills.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdWaterBills.Load(fsWaterBills);
    
                        /* Use XPath to locate the water bill that has 
                         * the same invoice number as the one in the Water Bill Number text box.
                         * Store the water bill in an XmlNodeList variable. */
                        XmlNodeList xnlWaterBills = xdWaterBills.DocumentElement!.SelectNodes("//bill-number[.='" + txtBillNumber.Text + "']")!;
    
                        foreach (XmlNode xnWaterBill in xnlWaterBills)
                        {
                            txtBillNumber.Text            =                xnWaterBill.FirstChild!.InnerText;
                            txtAccountNumber.Text         =                xnWaterBill.NextSibling!.InnerText;
                            txtMeterReadingStartDate.Text = DateTime.Parse(xnWaterBill.NextSibling.NextSibling!.InnerText).ToLongDateString();
                            txtMeterReadingEndDate.Text   = DateTime.Parse(xnWaterBill.NextSibling.NextSibling.NextSibling!.InnerText).ToLongDateString();
                            txtBillingDays.Text           =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText;
                            txtCounterReadingStart.Text   =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.InnerText;
                            txtCounterReadingEnd.Text     =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtTotalHCF.Text              =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtTotalGallons.Text          =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtFirstTierConsumption.Text  =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtSecondTierConsumption.Text =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtLastTierConsumption.Text   =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtWaterCharges.Text          =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtSewerCharges.Text          =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtEnvironmentCharges.Text    =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtServiceCharges.Text        =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtTotalCharges.Text          =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtStateTaxes.Text            =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtLocalTaxes.Text            =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtPaymentDueDate.Text        = DateTime.Parse(xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText).ToLongDateString();
                            txtAmountDue.Text             =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtLatePaymentDueDate.Text    = DateTime.Parse(xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText).ToLongDateString();
                            txtLateAmountDue.Text         =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                        }
                    }
                }
    
                XmlDocument xdCustomers = new XmlDocument();
                // Declare a variable for a file that holds the list of customers
                string? strCustomers = @"C:\Stellar Water Point6\Customers.xml";
    
                // Create a FileInfo object for the customers
                FileInfo? fiCustomers = new FileInfo(strCustomers);
    
                // We will need to know the water meter associated with this customer account
                string strMeterNumber = string.Empty;
    
                // Check whether the file that holds a list of customers exists
                if (fiCustomers.Exists)
                {
                    // If that exists, open it and pass it to a FileStream object
                    using (FileStream? fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        // Get the list of customers and pass the records to the XML DOM object created earlier
                        xdCustomers.Load(fsCustomers);
                        // Create an XmlNodeList list of customers using XPath
                        XmlNodeList xnlCustomers = xdCustomers.DocumentElement!.SelectNodes("//account-number[.='" + txtAccountNumber.Text + "']")!;
    
                        // Check each node of the XML record and display its values in each Windows control on the form
                        foreach (XmlNode xnCustomer in xnlCustomers)
                        {
                            //mtbAccountNumber.Text = xnCustomer.NextSibling!.InnerText;   // Meter #
                            txtAccountName.Text = xnCustomer.NextSibling!.InnerText; // Account Name
    
                            strMeterNumber = xnCustomer.NextSibling.NextSibling!.InnerText;   // Meter Number
                            txtAccountType.Text = xnCustomer.NextSibling.NextSibling.NextSibling!.InnerText;   // Account Type
                            txtAddress.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText;   // Address
                            txtCity.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText;   // City
                            txtCounty.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.InnerText;   // County
                            txtState.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;   // State
                            txtZIPCode.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText; // ZIP-Code
                        }
                    }
                }
    
                // Create an XML DOM object for the water meters records
                XmlDocument xdWaterMeters = new XmlDocument();
                // Declare a variable for a file that holds the list of water meters
                string? strWaterMeters = @"C:\Stellar Water Point6\WaterMeters.xml";
    
                // Create a FileInfo object for the customers
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                // Check whether the file that holds a list of water meters exists
                if (fiWaterMeters.Exists)
                {
                    // Get the list of water meters and pass the records to the XML DOM object
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        // Get the list of water meters and pass the records to the XML DOM object
                        xdWaterMeters.Load(fsWaterMeters);
                        // Create an XmlNodeList list of water meters using XPath
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + strMeterNumber + "']")!;
    
                        // Check each node of the XML record
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            /* Get the values for the water meter.
                             * Create a sentence and display it in the Meter Details text box. */
                            txtMeterDetails.Text = xnWaterMeter.NextSibling!.InnerText + " " +
                                                   xnWaterMeter.NextSibling.NextSibling!.InnerText + " (Meter Size: " +
                                                   xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText + ")";
                        }
                    }
                }
            }
        }
    }
  11. Return to the Water Bills - Delete form and double-click the Delete Water Bill button
  12. Return to the form and double-click the Close button
  13. Change the document as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.WaterBills
    {
        public partial class Delete : Form
        {
            public Delete()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterBill_Click(object sender, EventArgs e)
            {
                /* If the user clicks the Find Water Meter button, 
                 * make sure there is an invoice number in the top text box. */
                if (string.IsNullOrEmpty(txtBillNumber.Text))
                {
                    MessageBox.Show("You must provide a water bill number and then click the Find Water Bill button.",
                                    "Stellar Water Point", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    // If the user didn't type a bill number but clicked Find Water Bill, don't do anything
                    return;
                }
    
                XmlDocument xdWaterBills = new XmlDocument();
                string? strWaterBills = @"C:\Stellar Water Point6\WaterBills.xml";
    
                FileInfo? fiWaterBills = new FileInfo(strWaterBills);
    
                if (fiWaterBills.Exists)
                {
                    using (FileStream? fsWaterBills = new FileStream(fiWaterBills.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdWaterBills.Load(fsWaterBills);
    
                        /* Use XPath to locate the water bill that has 
                         * the same invoice number as the one in the Water Bill Number text box.
                         * Store the water bill in an XmlNodeList variable. */
                        XmlNodeList xnlWaterBills = xdWaterBills.DocumentElement!.SelectNodes("//bill-number[.='" + txtBillNumber.Text + "']")!;
    
                        foreach (XmlNode xnWaterBill in xnlWaterBills)
                        {
                            txtBillNumber.Text            =                xnWaterBill.FirstChild!.InnerText;
                            txtAccountNumber.Text         =                xnWaterBill.NextSibling!.InnerText;
                            txtMeterReadingStartDate.Text = DateTime.Parse(xnWaterBill.NextSibling.NextSibling!.InnerText).ToLongDateString();
                            txtMeterReadingEndDate.Text   = DateTime.Parse(xnWaterBill.NextSibling.NextSibling.NextSibling!.InnerText).ToLongDateString();
                            txtBillingDays.Text           =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText;
                            txtCounterReadingStart.Text   =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.InnerText;
                            txtCounterReadingEnd.Text     =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtTotalHCF.Text              =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtTotalGallons.Text          =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtFirstTierConsumption.Text  =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtSecondTierConsumption.Text =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtLastTierConsumption.Text   =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtWaterCharges.Text          =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtSewerCharges.Text          =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtEnvironmentCharges.Text    =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtServiceCharges.Text        =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtTotalCharges.Text          =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtStateTaxes.Text            =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtLocalTaxes.Text            =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtPaymentDueDate.Text        = DateTime.Parse(xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText).ToLongDateString();
                            txtAmountDue.Text             =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                            txtLatePaymentDueDate.Text    = DateTime.Parse(xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText).ToLongDateString();
                            txtLateAmountDue.Text         =                xnWaterBill.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;
                        }
                    }
                }
    
                XmlDocument xdCustomers = new XmlDocument();
                // Declare a variable for a file that holds the list of customers
                string? strCustomers = @"C:\Stellar Water Point6\Customers.xml";
    
                // Create a FileInfo object for the customers
                FileInfo? fiCustomers = new FileInfo(strCustomers);
    
                // We will need to know the water meter associated with this customer account
                string strMeterNumber = string.Empty;
    
                // Check whether the file that holds a list of customers exists
                if (fiCustomers.Exists)
                {
                    // If that exists, open it and pass it to a FileStream object
                    using (FileStream? fsCustomers = new FileStream(fiCustomers.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        // Get the list of customers and pass the records to the XML DOM object created earlier
                        xdCustomers.Load(fsCustomers);
                        // Create an XmlNodeList list of customers using XPath
                        XmlNodeList xnlCustomers = xdCustomers.DocumentElement!.SelectNodes("//account-number[.='" + txtAccountNumber.Text + "']")!;
    
                        // Check each node of the XML record and display its values in each Windows control on the form
                        foreach (XmlNode xnCustomer in xnlCustomers)
                        {
                            //mtbAccountNumber.Text = xnCustomer.NextSibling!.InnerText;   // Meter #
                            txtAccountName.Text = xnCustomer.NextSibling!.InnerText; // Account Name
    
                            strMeterNumber = xnCustomer.NextSibling.NextSibling!.InnerText;   // Meter Number
                            txtAccountType.Text = xnCustomer.NextSibling.NextSibling.NextSibling!.InnerText;   // Account Type
                            txtAddress.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText;   // Address
                            txtCity.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText;   // City
                            txtCounty.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.InnerText;   // County
                            txtState.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText;   // State
                            txtZIPCode.Text = xnCustomer.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText; // ZIP-Code
                        }
                    }
                }
    
                // Create an XML DOM object for the water meters records
                XmlDocument xdWaterMeters = new XmlDocument();
                // Declare a variable for a file that holds the list of water meters
                string? strWaterMeters = @"C:\Stellar Water Point6\WaterMeters.xml";
    
                // Create a FileInfo object for the customers
                FileInfo? fiWaterMeters = new FileInfo(strWaterMeters);
    
                // Check whether the file that holds a list of water meters exists
                if (fiWaterMeters.Exists)
                {
                    // Get the list of water meters and pass the records to the XML DOM object
                    using (FileStream? fsWaterMeters = new FileStream(fiWaterMeters.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        // Get the list of water meters and pass the records to the XML DOM object
                        xdWaterMeters.Load(fsWaterMeters);
                        // Create an XmlNodeList list of water meters using XPath
                        XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.SelectNodes("//meter-number[.='" + strMeterNumber + "']")!;
    
                        // Check each node of the XML record
                        foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                        {
                            /* Get the values for the water meter.
                             * Create a sentence and display it in the Meter Details text box. */
                            txtMeterDetails.Text = xnWaterMeter.NextSibling!.InnerText + " " +
                                                   xnWaterMeter.NextSibling.NextSibling!.InnerText + " (Meter Size: " +
                                                   xnWaterMeter.NextSibling.NextSibling.NextSibling!.InnerText + ")";
                        }
                    }
                }
            }
    
            private void btnDeleteWaterBill_Click(object sender, EventArgs e)
            {
                XmlDocument xdWaterMeters = new XmlDocument();
                string? strWaterMeters = @"C:\Stellar Water Point6\WaterBills.xml";
    
                if (string.IsNullOrEmpty(txtBillNumber.Text))
                {
                    MessageBox.Show("You must provide a bill number for the water bill you want to delete.",
                                    "Stellar Water Point", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }
    
                if (!File.Exists(strWaterMeters))
                {
                    MessageBox.Show("There is no file for the water bills in the system.",
                                    "Stellar Water Point",
                                    MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }
    
                xdWaterMeters.Load(strWaterMeters);
    
                XmlNodeList xnlWaterMeters = xdWaterMeters.DocumentElement!.GetElementsByTagName("bill-number");
    
                foreach (XmlNode xnWaterMeter in xnlWaterMeters)
                {
                    if (xnWaterMeter.InnerText == txtBillNumber.Text)
                    {
                        if (MessageBox.Show("Are you sure you want to delete this water bill from the system?",
                                            "Stellar Water Point",
                                            MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                        {
                            xdWaterMeters.DocumentElement.RemoveChild(xnWaterMeter.ParentNode!);
                            break;
                        }
                    }
                }
    
                xdWaterMeters.Save(strWaterMeters);
    
                Close();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  14. In the Solution Explorer, below the WaterBills folder, double-click Central.cs to open its form
  15. From the Toolbox, add two buttons to the form below the list view and to the right of the Edit Water Bill button
  16. Change the form design as follows:

    Stellar Water Point - Water Bills

    Control (Name) Text Other Properties
    ListView List View lvwWaterBills   Anchor: Bottom, Top, Bottom, Left, Right
    Button Button btnCreateWaterBill &Create Water Bill... Anchor: Bottom, Right
    Button Button btnViewWaterBill &View Water Bill... Anchor: Bottom, Right
    Button Button btnEditWaterBill &Edit Water Bill... Anchor: Bottom, Right
    Button Button btnDeleteWaterBill &Delete Water Bill... Anchor: Bottom, Right
    Button Button btnClose &Close Anchor: Bottom, Right
  17. On the form, double-click the Delete Water Bill button
  18. Return to the Water Bills - Central form and double-click the Close button
  19. Implement the events as follows:
    using System.Xml;
    
    namespace StellarWaterPoint3.WaterBills
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowWaterBills()
            {
                lvwWaterBills.Items.Clear();
    
                XmlDocument xdWaterBills = new XmlDocument();
                string? strWaterBills = @"C:\Stellar Water Point6\WaterBills.xml";
    
                FileInfo? fiWaterBills = new FileInfo(strWaterBills);
    
                if (fiWaterBills.Exists)
                {
                    using (FileStream? fsWaterBills = new FileStream(fiWaterBills.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        xdWaterBills.Load(fsWaterBills);
                        XmlNodeList xnlWaterBills = xdWaterBills.DocumentElement!.ChildNodes;
    
                        int i = 1;
    
                        foreach (XmlNode xnWaterBill in xnlWaterBills)
                        {
                            ListViewItem lviWaterBill = new ListViewItem(i.ToString());
    
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild!.InnerText);   // Water Bill #
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling!.InnerText);   // Account Number
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling!.InnerText); // Meter Reading Start Date
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling!.InnerText);   // Meter Reading End Date
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling!.InnerText); // Billing Days
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.InnerText);  // Counter Reading Start
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.InnerText);   // Counter Reading End
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText);   // Total HCF
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText);   // Gallons
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText);   // Payment Due Date
                            lviWaterBill.SubItems.Add(xnWaterBill.FirstChild.NextSibling.NextSibling.NextSibling.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.NextSibling!.InnerText);  // Amount Due
    
                            lvwWaterBills.Items.Add(lviWaterBill);
    
                            i++;
                        }
                    }
                }
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                ShowWaterBills();
            }
    
            private void btnCreateWaterBill_Click(object sender, EventArgs e)
            {
                Create create = new();
    
                create.ShowDialog();
    
                ShowWaterBills();
            }
    
            private void btnViewWaterBill_Click(object sender, EventArgs e)
            {
                Details details = new();
    
                details.ShowDialog();
            }
    
            private void btnEditWaterBill_Click(object sender, EventArgs e)
            {
                Editor editor = new();
    
                if (editor.ShowDialog() == DialogResult.OK)
                {
                    if (string.IsNullOrEmpty(editor.txtBillNumber.Text))
                    {
                        MessageBox.Show("You must first type a bill number and then click the Find Water Bill button. " +
                                        "You can then optionally change some values on the water bill and save it.",
                                        "Stellar Water Point", MessageBoxButtons.OK);
                        return;
                    }
    
                    // Create an XML DOM object
                    XmlDocument xdWaterBills = new XmlDocument();
                    // Prepare the path and name of the file that holds a list of water bills 
                    string? strWaterBills = @"C:\Stellar Water Point6\WaterBills.xml";
    
                    // Get the water bills records and store them in the above XML DOM object
                    xdWaterBills.Load(strWaterBills);
    
                    /* Create an XmlNodeList list that reprensents the XML elements from the list of water bills.
                     * Call the XML DOM's GetElementsByTagName() method. 
                     * To use the bill number elements as reference, pass the water bill number element as argument. */
                    XmlNodeList xnlWaterBills = xdWaterBills.DocumentElement!.GetElementsByTagName("bill-number");
    
                    // Visit each XML element of the list of water bills
                    foreach (XmlNode xnWaterBill in xnlWaterBills)
                    {
                        /* When you get to an element, find out if the value of its bill number is 
                         * the same as the bill number the user typed in the form. If that's the case, 
                         * change the value of each node of that element, using the values from the form. */
                        if (xnWaterBill.InnerText.Contains(editor.txtBillNumber.Text))
                        {
                            xnWaterBill.ParentNode!.InnerXml =
                                "<bill-number>"              + editor.txtBillNumber.Text            + "</bill-number>"                                   +
                                "<account-number>"           + editor.mtbAccountNumber.Text         + "</account-number>"                                +
                                "<meter-reading-start-date>" + editor.dtpMeterReadingStartDate.Value.ToShortDateString() + "</meter-reading-start-date>" +
                                "<meter-reading-end-date>"   + editor.dtpMeterReadingEndDate.Value.ToShortDateString()   + "</meter-reading-end-date>"   +
                                "<billing-days>"             + editor.txtBillingDays.Text           + "</billing-days>"                                  +
                                "<counter-reading-start>"    + editor.txtCounterReadingStart.Text   + "</counter-reading-start>"                         +
                                "<counter-reading-end>"      + editor.txtCounterReadingEnd.Text     + "</counter-reading-end>"                           +
                                "<total-hcf>"                + editor.txtTotalHCF.Text              + "</total-hcf>"                                     +
                                "<total-gallons>"            + editor.txtTotalGallons.Text          + "</total-gallons>"                                 +
                                "<first-tier-consumption>"   + editor.txtFirstTierConsumption.Text  + "</first-tier-consumption>"                        +
                                "<second-tier-consumption>"  + editor.txtSecondTierConsumption.Text + "</second-tier-consumption>"                       +
                                "<last-tier-consumption>"    + editor.txtLastTierConsumption.Text   + "</last-tier-consumption>"                         +
                                "<water-charges>"            + editor.txtWaterCharges.Text          + "</water-charges>"                                 +
                                "<sewer-charges>"            + editor.txtSewerCharges.Text          + "</sewer-charges>"                                 +
                                "<environment-charges>"      + editor.txtEnvironmentCharges.Text    + "</environment-charges>"                           +
                                "<service-charges>"          + editor.txtEnvironmentCharges.Text    + "</service-charges>"                               +
                                "<total-charges>"            + editor.txtTotalCharges.Text          + "</total-charges>"                                 +
                                "<state-taxes>"              + editor.txtStateTaxes.Text            + "</state-taxes>"                                   +
                                "<local-taxes>"              + editor.txtLocalTaxes.Text            + "</local-taxes>"                                   +
                                "<payment-due-date>"         + editor.dtpPaymentDueDate.Value.ToShortDateString() + "</payment-due-date>"                +
                                "<amount-due>"               + editor.txtAmountDue.Text             + "</amount-due>"                                    +
                                "<late-payment-due-date>"    + editor.dtpLatePaymentDueDate.Value.ToShortDateString() + "</late-payment-due-date>"       +
                                "<late-amount-due>"          + editor.txtLateAmountDue.Text         + "</late-amount-due>";
    
                            // After updating the elements, save the updated file
                            xdWaterBills.Save(strWaterBills);
                            // After saving the file, stop searching
                            break;
                        }
                    }
                }
    
                /* Now that the user has closed the Water Bill - Editor dialog box (and probably 
                 * updated the XML file for water bills), (re-)display the list of water bills.*/
                ShowWaterBills();
            }
    
            private void btnDeleteWaterBill_Click(object sender, EventArgs e)
            {
                Delete delete = new();
    
                delete.ShowDialog();
    
                ShowWaterBills();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  20. To execute, on the main menu, click Debug -> Start Without Debugging:

  21. On the Stellar Water Point form, click the Water Bills button

    Stellar Water Point - Water Bill Processing

  22. On the Water Bills form, click the Delete Water Bill button

    Stellar Water Point - Water Bill Deletion

  23. In the Water Bill # text box, type 917829

    Stellar Water Point - Water Bill Deletion

  24. Click Find Water Bill

    Stellar Water Point - Water Bill Deletion

  25. Click Delete Water Bill
  26. Read the message in the message box and click Yes:

    Stellar Water Point - Water Bills

  27. Close the forms and return to your programming environment
  28. From the Windows Explorer, open the WaterBills.xml file
  29. Replace the content of the file with the provided file
  30. Save the file
  31. Return to your programming environment
  32. Close Microsoft Visual Studio

Application


Home Copyright © 2010-2025, FunctionX Sunday 30 March 2025, 13:50 Home