Application Setup

Introduction

In this exercise, we will create a semi-small graphical application for a water distribution company that provides water for various types of customers, including residential families, private businesses, government buildings, etc. The application uses a text-based database that processes records using collection classes. The records are saved in JSON files.

Practical LearningPractical Learning: Introducing the Application

  1. Start Microsoft Visual Studio
  2. In the Visual Studio 2026 dialog box, click Create a New Project
  3. In the Create a New Project dialog box, in the Languages combo box, select C#
  4. In the list of projects templates, click Windows Forms App
  5. Click Next
  6. Change the Project Name to StellarWaterPoint2
  7. Click Next
  8. In the Framework combo box, select the highest version: .NET 10.0 (Long Term Support)
  9. Click Create
  10. To create a folder, in the Solution Explorer -> Add -> Folder
  11. Type Models as the name of the folder
  12. To create a class, in the Solution Explorer, right-click Models -> Add -> Class...
  13. Type MsgBox as the name of the file and class
  14. Click Add
  15. Change the class as follows:
    namespace StellarWaterPoint2.Models
    {
        public enum Answer { No = 0, Yes = 1, Cancel = 2, Unknown = 3 }
    
        internal static class MsgBox
        {
            public static void Show(string message)
            {
                MessageBox.Show(message,
                                "Stellar Water Point",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Information);
            }
    
            public static Answer Question(string message)
            {
                DialogResult result = MessageBox.Show(message,
                                                      "Stellar Water Point",
                                                      MessageBoxButtons.YesNoCancel,
                                                      MessageBoxIcon.Question);
    
                switch (result)
                {
                    case DialogResult.Yes:
                        return Answer.Yes;
                    case DialogResult.No:
                        return Answer.No;
                    case DialogResult.Cancel:
                        return Answer.Cancel;
                    default:
                        return Answer.Unknown;
                }
            }
        }
    }
  16. In the Solution Explorer, right-click Models -> Add -> Class
  17. Set the file Name to Repository
  18. Click Add

The Main Form of the Application

Our application will use a central form acting as a switchboard from which other section-based forms can be accessed.

Practical LearningPractical Learning: Preparing the Main 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. Implement the event as follows:
    namespace StellarWaterPoint2
    {
        public partial class WaterDistribution : Form
        {
            public WaterDistribution()
            {
                InitializeComponent();
            }
    
            private void WaterDistribution_Load(object sender, EventArgs e)
            {
                Directory.CreateDirectory(@"C:\Stellar Water Point2");
            }
        }
    }

Water Meters

Introduction

The company of our application uses water meters to monitor the amount of water its customers consume. To start, the application needs a list of water meters that are available.

Practical LearningPractical Learning: Displaying Water Meters

  1. To create a class, in the Solution Explorer, right-click Models -> Add -> Class...
  2. On the main menu, click Project -> Add Class...
  3. Replace the name with WaterMeter
  4. Click Add
  5. Change the code as follows:
    namespace StellarWaterPoint2.Models
    {
        internal record WaterMeter
        {
            public int     WaterMeterId { get; set; }
            public string? MeterNumber  { get; set; }
            public string? Make         { get; set; }
            public string? Model        { get; set; }
            public string? MeterSize    { get; set; }
        }
    }
  6. In the Solution Explorer, right-click StellarWaterPoint1 -> Add -> New Folder
  7. 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. For 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 TextAlign
    colWaterMeterId Water Meter Id 150  
    colMeterNumber Meter # 150 Center
    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
  9. Doubte-click an unoccupied area of the form to generate its Load event
  10. Change the document as follows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.WaterMeters
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowWaterMeters()
            {
                string strWaterMeters = string.Empty;
                List<WaterMeter> waterMeters = new List<WaterMeter>();
                string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
                FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
                if (fiWaterMeters.Exists == true)
                {
                    using (TextReader trWaterMeters = new StreamReader(fiWaterMeters.FullName))
                    {
                        strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
                        waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
    
                        lvwWaterMeters.Items.Clear();
    
                        foreach (WaterMeter wm in waterMeters)
                        {
                            ListViewItem lviWaterMeter = new ListViewItem(wm.WaterMeterId.ToString());
    
                            lviWaterMeter.SubItems.Add(wm.MeterNumber);
                            lviWaterMeter.SubItems.Add(wm.Make);
                            lviWaterMeter.SubItems.Add(wm.Model);
                            lviWaterMeter.SubItems.Add(wm.MeterSize);
    
                            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 StellarWaterPoint2
    {
        public partial class WaterDistribution : Form
        {
            public WaterDistribution()
            {
                InitializeComponent();
            }
    
            private void WaterDistribution_Load(object sender, EventArgs e)
            {
                Directory.CreateDirectory(@"C:\Stellar Water Point2");
            }
    
            private void btnWaterMeters_Click(object sender, EventArgs e)
            {
                WaterMeters.Central central = new WaterMeters.Central();
    
                central.Show();
            }
        }
    }

A Water Meter Record

A water meter must be installed in the location where water is consumed. We will create a form that allows a user to create a new record for a water meter.

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. Type Create
  3. 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
    Modifiers: Public
    Label Label   &Water Meter Id:  
    TextBox Text Box txtWaterMeterId   Modifiers: Public
    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
  4. Using the Properties window, change some characteristics of the form as follows:
    FormBorderStyle: FixedDialog
    Text:            Stellar Water Point - Create Water Meter
    StartPosition:   CenterScreen
    AcceptButton:    btnOK
    CancelButton:    btnCancel
  5. Double-click an unoccupied area of the form to generate its Load event
  6. Implement the event as follows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.WaterMeters
    {
        public partial class Create : Form
        {
            public Create()
            {
                InitializeComponent();
            }
    
            private void Create_Load(object sender, EventArgs e)
            {
                string strWaterMeters = string.Empty;
                List<WaterMeter> waterMeters = new List<WaterMeter>();
                string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
                FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
        
                int waterMeterId = 0;
                
                if (fiWaterMeters.Exists == true)
                {
    
                    using (TextReader trWaterMeters = new StreamReader(fiWaterMeters.FullName))
                    {
                        strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
                        waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
    
                        foreach (WaterMeter wm in waterMeters)
                        {
                            waterMeterId = wm.WaterMeterId;
                        }
                    }
                }
                
                txtWaterMeterId.Text = (waterMeterId + 1).ToString();
            }
        }
    }
  7. In the Solution Explorer, below the WaterMeters folder, double-click Central.cs
  8. From the Toolbox, add a button to the form below the list view
  9. Change the characteristics of the button as follows:

    Stellar Water Point - Water Meters

    Control (Name) Text
    ListView List View No Change No Change
    Button Button btnNewWaterMeter &New Water Meter...
  10. On the Central form, double-click the New Water Meter button
  11. Implement the event as follows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.WaterMeters
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowWaterMeters()
            {
                . . .
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                ShowWaterMeters();
            }
    
            private void btnNewWaterMeter_Click(object sender, EventArgs e)
            {
                            Create create = new();
    
                if (create.ShowDialog() == DialogResult.OK)
                {
                    if(create.mtbMeterNumber.Text.Replace("-", "").Trim() == "")
                    {
                        MsgBox.Show("You must type a meter number. " +
                                    "Otherwise, the water meter cannot be set up.");
                        return;
                    }
    
                    string strWaterMeters = string.Empty;
                    List<WaterMeter> waterMeters = new List<WaterMeter>();
                    string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
                    FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
                    if (fiWaterMeters.Exists == true)
                    {
                        strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
                        waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
                    }
    
                    WaterMeter wm = new WaterMeter()
                    {
                        WaterMeterId = create.txtWaterMeterId.Text == "" ? 1 : int.Parse(create.txtWaterMeterId.Text),
                        MeterNumber = create.mtbMeterNumber.Text,
                        Make = create.txtMake.Text,
                        Model = create.txtModel.Text,
                        MeterSize = create.txtMeterSize.Text
                    };
    
                    waterMeters.Add(wm);
    
                    JsonSerializerOptions options = new JsonSerializerOptions();
                    options.WriteIndented = true;
    
                    string jsWaterMeters = JsonSerializer.Serialize(waterMeters, typeof(List<WaterMeter>), options);
                    File.WriteAllText(fiWaterMeters.FullName, jsWaterMeters);
                }
    
                ShowWaterMeters();
            }
        }
    }
  12. To execute the application, on the main menu, click Debug -> Start Without Debugging

    Stellar Water Point

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

    Stellar Water Point - Water Meters

  14. Click the New Water Meter button:

    Stellar Water Point - New Water Meter

  15. 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

  16. Close the forms and return to your programming environment
  17. In the Solution Explorer, double-click WaterDistribution.cs to access the primary form of the application
  18. Double-click an unoccupied area of the form to access its code
  19. Comment the call of the AccountType class as follows:
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2
    {
        public partial class WaterDistribution : Form
        {
            public WaterDistribution()
            {
                InitializeComponent();
            }
    
            private void WaterDistribution_Load(object sender, EventArgs e)
            {
                Directory.CreateDirectory(@"C:\Stellar Water Point2");            
            }
    
            private void btnWaterMeters_Click(object sender, EventArgs e)
            {
                WaterMeters.Central central = new();
    
                central.Show();
            }
        }
    }

Water Meter Details

When the records of water meters have been created, sometimes, a user may want to view some details about a water meter. We are going to create such a form.

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. Design the form as follows:

    Stellar Water Point - New Water Meter

    Control (Name) Text Enabled Modifiers Other Properties
    Label Label   &Meter #:      
    MaskedTextBox Masked Text Box mtbMeterNumber   False Public Masked: 000-000-000
    Button Button btnFindWaterMeter &Find Water Meter      
    Label Label   Make:      
    TextBox Text Box txtMake   False Public  
    Label Label   Model:      
    TextBox Text Box txtModel   False Public  
    Label Label   Meter Size:      
    TextBox Text Box txtMeterSize   False Public  
    Label Label   Water Meter Id:      
    TextBox Text Box txtWaterMeterId   False Public  
    Button Button btnClose &Close      
  5. On the form, double-click the Find Water Meter button
  6. Change the document as follows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.WaterMeters
    {
        public partial class Details : Form
        {
            public Details()
            {
                InitializeComponent();
            }
    
            private void btnFindWateMeter_Click(object sender, EventArgs e)
            {
                if (string.IsNullOrEmpty(mtbMeterNumber.Text))
                {
                    MsgBox.Show("You must type a valid meter number, " +
                                    "and then click the Find Water Meter button.",
                                    "Stellar Water Point", MessageBoxButtons.OK);
                    return;
                }
    
                string strWaterMeters = string.Empty;
                List<WaterMeter> waterMeters = new List<WaterMeter>();
                string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
                FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
                if (fiWaterMeters.Exists == true)
                {
                    strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
                    waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
    
                    foreach (WaterMeter meter in waterMeters)
                    {
                        if (meter.MeterNumber == mtbMeterNumber.Text)
                        {
                            txtMake.Text = meter.Make;
                            txtModel.Text = meter.Model;
                            txtMeterSize.Text = meter.MeterSize;
                        }
                    }
                }
            }
        }
    }
  7. Return to the form and double-click the Close button
  8. Change the document as follows:
    private void btnClose_Click(object sender, EventArgs e)
    {
        Close();
    }
  9. In the Solution Explorer, below the WaterMeters folder, double-click Central.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 New Water Meter button
  11. Change the characteristics of the button as follows:

    Stellar Water Point - Water Meters

    Control (Name) Other Properties
    ListView List View No Change No Change
    Button Button No Change No Change
    Button Button btnViewWaterMeter &View Water Meter...
  12. Double-click the View Water Meter button
  13. Change the document as follows:
    private void btnViewWaterMeter_Click(object sender, EventArgs e)
    {
        Details view = new();
                
        view.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 Meters button
  16. On the Central form of water meters, click the View Water Meter button:

    Stellar Water Point - View Water Meter

  17. In the Meter # text, type 392-494-572
  18. Click the Find Water Button button:

    Stellar Water Point - View Water Meter

  19. 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. Design the form as follows:

    Stellar Water Point - New Water Meter

    Control (Name) Text Enabled Other Properties
    Label Label   &Meter #:    
    MaskedTextBox Masked Text Box mtbMeterNumber   False Masked: 000-000-000
    Button Button btnFindWaterMeter &Find Water Meter    
    Label Label   Make:    
    TextBox Text Box txtMake   False  
    Label Label   Model:    
    TextBox Text Box txtModel   False  
    Label Label   Meter Size:    
    TextBox Text Box txtMeterSize   False  
    Button Button btnUpdateWaterMeter &Update Water Meter    
    Button Button btnClose &Close    
  5. On the form, double-click the Find Water Meter button
  6. Change the document as follows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.WaterMeters
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterMeter_Click(object sender, EventArgs e)
            {
                if (mtbMeterNumber.Text.Replace("-", "").Trim().Equals(string.Empty))
                {
                    MsgBox.Show("Please provide a meter number, " +
                                "and then click the Find Water Meter button.");
                    return;
                }
    
                string strWaterMeters = string.Empty;
                List<WaterMeter> waterMeters = new List<WaterMeter>();
                string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
                FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
                if (fiWaterMeters.Exists == true)
                {
                    strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
                    waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
    
                    foreach (WaterMeter meter in waterMeters)
                    {
                        if (meter.MeterNumber == mtbMeterNumber.Text)
                        {
                            txtWaterMeterId.Text = meter.WaterMeterId.ToString();
                            txtMake.Text = meter.Make;
                            txtModel.Text = meter.Model;
                            txtMeterSize.Text = meter.MeterSize;
                        }
                    }
                }
            }
        }
    }
  7. Return to the form and double-click the Update Water Meter button
  8. Change the document as follows:
    private void btnUpdateWaterMeter_Click(object sender, EventArgs e)
    {
        if (string.IsNullOrEmpty(mtbMeterNumber.Text))
        {
            MsgBox.Show("You must type a valid meter number, " +
                        "and then click the Find Water Meter button.");
            return;
        }
    
        string strWaterMeters = string.Empty;
        List<WaterMeter> waterMeters = new List<WaterMeter>();
        string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
        FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
        if (fiWaterMeters.Exists == true)
        {
            strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
            waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
    
            WaterMeter? meter = waterMeters.Find(mtr => mtr.MeterNumber == mtbMeterNumber.Text);
    
            if (meter is not null)
            {
                meter.WaterMeterId = int.Parse(txtWaterMeterId.Text);
                meter.Make = txtMake.Text;
                meter.Model = txtModel.Text;
                meter.MeterSize = txtMeterSize.Text;
    
                JsonSerializerOptions options = new JsonSerializerOptions();
                options.WriteIndented = true;
    
                string jsWaterMeters = JsonSerializer.Serialize(waterMeters, typeof(List<WaterMeter>), options);
                File.WriteAllText(fiWaterMeters.FullName, jsWaterMeters);
            }
        }
    
        Close();
    }
  9. Return to the form and double-click the Close button
  10. Change the document as follows:
    private void btnClose_Click(object sender, EventArgs e)
    {
        Close();
    }
  11. In the Solution Explorer, below the WaterMeters folder, double-click Central.cs
  12. From the Toolbox, add a button to the form below the list view and on the right side of the View Water Meter button
  13. Change the characteristics of the button as follows:

    Stellar Water Point - Water Meters

    Control (Name) Other Properties
    ListView List View No Change No Change
    Button Button No Change No Change
    Button Button No Change No Change
    Button Button btnEditWaterMeter &Edit Water Meter...
  14. Display the Central form of the WaterMeters folder
  15. Double-click the Update Water Meter button
  16. Change the document as follows:
    private void btnEditWaterMeter_Click(object sender, EventArgs e)
    {
        Editor editor = new();
    
        editor.ShowDialog();
    
        ShowWaterMeters();
    }
  17. To execute the application, on the main menu, click Debug -> Start Without Debugging:

    Stellar Water Point

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

    Stellar Water Point - Water Meters

  19. Click the Update Water Meter button:

    Stellar Water Point - Water Meter Editor

  20. In the Meter # text, type 938-705-869
  21. Click the Find button

    Stellar Water Point - Water Meter Editor

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

    Stellar Water Point - Water Meter Editor

  23. Click the Update button:

    Stellar Water Point - Water Meters

  24. Close the forms and return to your programming environment

Removing a Water Meter from the Database

If a record of a water meter is not necessary anymore, a user can be asked to delete such a record. We are going to create a form for such an operation.

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. Design the form as follows:

    Stellar Water Point - Water Meter Deletion

    Control (Name) Text Enabled Other Properties
    Label Label   &Meter #:    
    MaskedTextBox Masked Text Box mtbMeterNumber   False Masked: 000-000-000
    Label Label   Make:    
    TextBox Text Box txtMake   False  
    Label Label   Model:    
    TextBox Text Box txtModel   False  
    Label Label   Meter Size:    
    TextBox Text Box txtMeterSize   False  
    Button Button btnClose &Close    
  5. On the form, double-click the Find Water Meter button
  6. Change the document as tollows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.WaterMeters
    {
        public partial class Delete : Form
        {
            public Delete()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterMeter_Click(object sender, EventArgs e)
            {
                if (mtbMeterNumber.Text.Replace("-", "").Trim().Equals(string.Empty))
                {
                    MsgBox.Show("Please provide a meter number, " +
                                "and then click the Find Water Meter button.");
                    return;
                }
    
                string strWaterMeters = string.Empty;
                List<WaterMeter> waterMeters = new List<WaterMeter>();
                string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
                FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
                if (fiWaterMeters.Exists == true)
                {
                    strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
                    waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
    
                    foreach (WaterMeter meter in waterMeters)
                    {
                        if (meter.MeterNumber == mtbMeterNumber.Text)
                        {
                            txtWaterMeterId.Text = meter.WaterMeterId.ToString();
                            txtMake.Text = meter.Make;
                            txtModel.Text = meter.Model;
                            txtMeterSize.Text = meter.MeterSize;
                        }
                    }
                }
            }
        }
    }
  7. Return to the form and double-click the Delete Water Meter button
  8. Change the document as tollows:
    private void btnDeleteWaterMeter_Click(object sender, EventArgs e)
    {
        if (mtbMeterNumber.Text.Replace(&quot;-&quot;, &quot;&quot;).Trim().Equals(string.Empty))
        {
            MsgBox.Show(&quot;You must type a valid meter number, &quot; +
                        &quot;and then click the Find Water Meter button.&quot;);
            return;
        }
    
        string strWaterMeters = string.Empty;
        List&lt;WaterMeter&gt; waterMeters = new List&lt;WaterMeter&gt;();
        string fileWaterMeters = @&quot;C:\Stellar Water Point2\WaterMeters.json&quot;;
    
        FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
        if (fiWaterMeters.Exists == true)
        {
            strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
            waterMeters = JsonSerializer.Deserialize&lt;List&lt;WaterMeter&gt;&gt;(strWaterMeters)!;
    
            WaterMeter meter = waterMeters.Find(mtr =&gt; mtr.MeterNumber == mtbMeterNumber.Text)!;
    
            if (meter is not null)
            {
                if (MsgBox.Question(&quot;Are you sure you want to delete this water meter &quot; +
                                    &quot;(you cannot undo the action)?&quot;) == Answer.Yes)
                {
                    waterMeters.Remove(meter);
    
                    JsonSerializerOptions options = new JsonSerializerOptions();
                    options.WriteIndented = true;
    
                    string jsWaterMeters = JsonSerializer.Serialize(waterMeters, typeof(List&lt;WaterMeter&gt;), options);
                    File.WriteAllText(fiWaterMeters.FullName, jsWaterMeters);
    
                    MsgBox.Show(&quot;The water meter has been removed from our database.&quot;);
                }
            }
        }
    
        Close();
    }
  9. Return to the form and double-click the Close button
  10. Change the document as tollows:
    private void btnClose_Click(object sender, EventArgs e)
    {
        Close();
    }
  11. In the Solution Explorer, below the WaterMeters folder, double-click Central.cs
  12. From the Toolbox, add two buttons to the form below the list view and on the right side of the Edit Water Meter button
  13. Change the characteristics of the buttons as follows:

    Stellar Water Point - Water Meters

    Control (Name) Text Anchor
    ListView List View lvwWaterMeters   Top, Bottom, Left, Right
    Button Button btnNewWaterMeter &New Water Meter... Bottom, Right
    Button Button btnViewWaterMeter &View Water Meter... Bottom, Right
    Button Button btnEditWaterMeter &Edit Water Meter... Bottom, Right
    Button Button btnDeleteWateMeter &Delete Water Meter... Bottom, Right
    Button Button btnClose &Close Bottom, Right
  14. On the form, double-click the Delete Water Meter button
  15. Return to the Central form of the water meters and double-click the Close button
  16. Change the document as follows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.WaterMeters
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowWaterMeters()
            {
                string strWaterMeters = string.Empty;
                List<WaterMeter> waterMeters = new List<WaterMeter>();
                string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
                FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
                if (fiWaterMeters.Exists == true)
                {
                    using (TextReader trWaterMeters = new StreamReader(fiWaterMeters.FullName))
                    {
                        strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
                        waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
    
                        lvwWaterMeters.Items.Clear();
    
                        foreach (WaterMeter wm in waterMeters)
                        {
                            ListViewItem lviWaterMeter = new ListViewItem(wm.WaterMeterId.ToString());
    
                            lviWaterMeter.SubItems.Add(wm.MeterNumber);
                            lviWaterMeter.SubItems.Add(wm.Make);
                            lviWaterMeter.SubItems.Add(wm.Model);
                            lviWaterMeter.SubItems.Add(wm.MeterSize);
    
                            lvwWaterMeters.Items.Add(lviWaterMeter);
                        }
                    }
                }
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                ShowWaterMeters();
            }
    
            private void btnNewWaterMeter_Click(object sender, EventArgs e)
            {
                Create create = new();
    
                if (create.ShowDialog() == DialogResult.OK)
                {
                    if (create.mtbMeterNumber.Text.Replace("-", "").Trim() == "")
                    {
                        MsgBox.Show("You must type a meter number. " +
                                    "Otherwise, the water meter cannot be set up.");
                        return;
                    }
    
                    string strWaterMeters = string.Empty;
                    List<WaterMeter> waterMeters = new List<WaterMeter>();
                    string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
                    FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
                    if (fiWaterMeters.Exists == true)
                    {
                        strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
                        waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
                    }
    
                    WaterMeter wm = new WaterMeter()
                    {
                        WaterMeterId = create.txtWaterMeterId.Text == "" ? 1 : int.Parse(create.txtWaterMeterId.Text),
                        MeterNumber = create.mtbMeterNumber.Text,
                        Make = create.txtMake.Text,
                        Model = create.txtModel.Text,
                        MeterSize = create.txtMeterSize.Text
                    };
    
                    waterMeters.Add(wm);
    
                    JsonSerializerOptions options = new JsonSerializerOptions();
                    options.WriteIndented = true;
    
                    string jsWaterMeters = JsonSerializer.Serialize(waterMeters, typeof(List<WaterMeter>), options);
                    File.WriteAllText(fiWaterMeters.FullName, jsWaterMeters);
                }
    
                ShowWaterMeters();
            }
    
            private void btnViewWaterMeter_Click(object sender, EventArgs e)
            {
                Details view = new();
    
                view.Show();
            }
    
            private void btnUpdateWaterMeter_Click(object sender, EventArgs e)
            {
                Editor editor = new();
    
                editor.ShowDialog();
    
                ShowWaterMeters();
            }
    
            private void btnDeleteWaterMeter_Click(object sender, EventArgs e)
            {
                Delete delete = new Delete();
    
                delete.ShowDialog();
    
                ShowWaterMeters();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  17. To execute the application, on the main menu, click Debug -> Start Without Debugging:

    Stellar Water Point - Water Meters

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

    Stellar Water Point - Water Meters

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

    Stellar Water Point - Water Meter Deletion

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

    Stellar Water Point - Water Meter Deletion

  22. Click the Delete button:

    Stellar Water Point - Water Meter Deletion

  23. Read the text on the message box and click Yes
  24. Read the other message box and click OK
  25. In the same way, delete the other two records
  26. Close the forms and return to your programming environment
  27. In the Solution Explorer, double-click WaterDistribution.cs
  28. Change the document as follows:
    using StellarWaterPoint2.Models;
    using System.Reflection.Metadata;
    using System.Text.Json;
    
    namespace StellarWaterPoint2
    {
        public partial class WaterDistribution : Form
        {
            private void CreateWaterMeters()
            {
                List<WaterMeter> waterMeters = new List<WaterMeter>();
    
                waterMeters!.Add(new WaterMeter() { WaterMeterId =  1, MeterNumber = "392-494-572", Make = "Constance Technologies", Model = "TG-4822",  MeterSize = "5/8 Inches"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId =  2, MeterNumber = "938-725-869", Make = "Stanford Trend",         Model = "266G",     MeterSize = "1 1/2 Inches" });
                waterMeters.Add(new WaterMeter()  { WaterMeterId =  3, MeterNumber = "588-279-663", Make = "Estellano",              Model = "NCF-226",  MeterSize = "4 Inches"     });
                waterMeters.Add(new WaterMeter()  { WaterMeterId =  4, MeterNumber = "186-962-805", Make = "Lansome",                Model = "2800",     MeterSize = "1 1/2 Inches" });
                waterMeters.Add(new WaterMeter()  { WaterMeterId =  5, MeterNumber = "379-386-979", Make = "Planetra",               Model = "P-2020",   MeterSize = "4 Inches"     });
                waterMeters.Add(new WaterMeter()  { WaterMeterId =  6, MeterNumber = "580-742-825", Make = "Kensa Sons",             Model = "KS2000A",  MeterSize = "1 3/4 Inches" });
                waterMeters.Add(new WaterMeter()  { WaterMeterId =  7, MeterNumber = "849-351-444", Make = "Raynes Energica",        Model = "a1088",    MeterSize = "2 Inches"     });
                waterMeters.Add(new WaterMeter()  { WaterMeterId =  8, MeterNumber = "208-428-308", Make = "Constance Technologies", Model = "808D",     MeterSize = "3/4 Inches"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId =  9, MeterNumber = "738-588-249", Make = "Warrington",             Model = "W4242",    MeterSize = "5/8 Inches"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 10, MeterNumber = "496-813-794", Make = "Estellano",              Model = "NCF-226",  MeterSize = "3/4 Inches"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 11, MeterNumber = "862-715-006", Make = "Warrington",             Model = "W-4040",   MeterSize = "1/2 Inch"     });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 12, MeterNumber = "649-358-184", Make = "Raynes Energica",        Model = "b1700",    MeterSize = "1 1/2 Inches" });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 13, MeterNumber = "928-317-924", Make = "Gongola",                Model = "GN1000",   MeterSize = "2 Inch"       });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 14, MeterNumber = "595-753-147", Make = "Grass Grill",            Model = "CRC-1000", MeterSize = "1 Inch"       });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 15, MeterNumber = "799-528-461", Make = "Kensa Sons",             Model = "K-584-L",  MeterSize = "3/4 Inches"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 16, MeterNumber = "386-468-057", Make = "Estellano",              Model = "NCF-226",  MeterSize = "3/4 Inches"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 17, MeterNumber = "938-275-294", Make = "Constance Technologies", Model = "TT-8822",  MeterSize = "4 Inches"     });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 18, MeterNumber = "288-427-585", Make = "Planetra",               Model = "P-2020",   MeterSize = "1/2 Inch"     });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 19, MeterNumber = "394-835-297", Make = "Raynes Energica",        Model = "i2022",    MeterSize = "3/4 Inches"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 20, MeterNumber = "847-252-246", Make = "Master Stream",          Model = "2000-MS",  MeterSize = "1 1/2 Inches" });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 21, MeterNumber = "349-725-848", Make = "Planetra",               Model = "P-8000",   MeterSize = "4 Inches"     });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 22, MeterNumber = "713-942-058", Make = "Master Stream",          Model = "3366-MS",  MeterSize = "3/4 Inches"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 23, MeterNumber = "747-581-379", Make = "Warrington",             Model = "W4242",    MeterSize = "5/8 Inches"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 24, MeterNumber = "582-755-263", Make = "Kensa Sons",             Model = "KS2000A",  MeterSize = "1 Inch"       });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 25, MeterNumber = "827-260-758", Make = "Raynes Energica",        Model = "a1088",    MeterSize = "1-1/4 Inch"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 26, MeterNumber = "837-806-836", Make = "Lansome",                Model = "7400",     MeterSize = "5/8 Inches"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 27, MeterNumber = "207-964-835", Make = "Constance Technologies", Model = "TG-6220",  MeterSize = "5/8 Inches"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 28, MeterNumber = "296-837-495", Make = "Raynes Energica",        Model = "QG505",    MeterSize = "4 Inches"     });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 29, MeterNumber = "468-359-486", Make = "Grass Grill",            Model = "KLP-8822", MeterSize = "1-1/4 Inch"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 30, MeterNumber = "931-486-003", Make = "Planetra",               Model = "P-2020",   MeterSize = "1/2 Inch"     });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 31, MeterNumber = "483-770-648", Make = "Warren",                 Model = "WWW",      MeterSize = "0.1 Inches"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 32, MeterNumber = "592-824-957", Make = "Kensa Sons",             Model = "D-497-H",  MeterSize = "3/4 Inches"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 33, MeterNumber = "293-835-704", Make = "Gongola",                Model = "GOL1000",  MeterSize = "1/2 Inch"     });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 34, MeterNumber = "739-777-749", Make = "Warrington",             Model = "W2200W",   MeterSize = "3/4 Inches"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 35, MeterNumber = "374-886-284", Make = "Raynes Energica",        Model = "i2022",    MeterSize = "3/4 Inches"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 36, MeterNumber = "186-959-757", Make = "Kensa Sons",             Model = "M-686-G",  MeterSize = "1 1/2 Inches" });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 37, MeterNumber = "594-827-359", Make = "Planetra",               Model = "P-8000",   MeterSize = "1 Inch"       });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 38, MeterNumber = "394-739-242", Make = "Master Stream",          Model = "9393-TT",  MeterSize = "5/8 Inches"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 39, MeterNumber = "529-283-752", Make = "Constance Technologies", Model = "404T",     MeterSize = "3/4 Inches"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 40, MeterNumber = "295-770-695", Make = "Warrington",             Model = "W-2286",   MeterSize = "1-1/4 Inch"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 41, MeterNumber = "739-749-737", Make = "Kensa Sons",             Model = "KS2000A",  MeterSize = "1 Inch"       });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 42, MeterNumber = "947-528-317", Make = "Gondola",                Model = "GDL-5000", MeterSize = "1 Inch"       });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 43, MeterNumber = "630-207-055", Make = "Lansome",                Model = "2800",     MeterSize = "3/4 Inches"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 44, MeterNumber = "827-508-248", Make = "Standard Trend",         Model = "428T",     MeterSize = "3/4 Inches"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 45, MeterNumber = "293-924-869", Make = "Grass Grill",            Model = "CRC-2020", MeterSize = "1/2 Inch"     });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 46, MeterNumber = "928-247-580", Make = "Gondola",                Model = "GOL2000",  MeterSize = "0.34 Inch"    });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 47, MeterNumber = "682-537-380", Make = "Planetra",               Model = "P-2020",   MeterSize = "1-1/4 Inch"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 48, MeterNumber = "470-628-850", Make = "Estellano",              Model = "WRT-482",  MeterSize = "3/4 Inches"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 49, MeterNumber = "649-373-505", Make = "Constance Technologies", Model = "BD-7000",  MeterSize = "5/8 Inches"   });
                waterMeters.Add(new WaterMeter()  { WaterMeterId = 50, MeterNumber = "306-842-497", Make = "Lansome",                Model = "9000",     MeterSize = "3/4 Inches"   });
    
                string strWaterMeters = string.Empty;
                string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
                JsonSerializerOptions options = new JsonSerializerOptions();
                options.WriteIndented = true;
    
                FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
                string jsWaterMeters = JsonSerializer.Serialize(waterMeters, typeof(List<WaterMeter>), options);
                File.WriteAllText(fiWaterMeters.FullName, jsWaterMeters);
            }
    
            private void CreateAccountsTypes()
            {
                List<AccountType> types = new List<AccountType>()
                {
                    new AccountType() { AccountTypeId = 1, TypeCode = "OTH", TypeDecription = "Other" },
                    new AccountType() { AccountTypeId = 3, TypeCode = "RES", TypeDecription = "Residential Household" },
                    new AccountType() { AccountTypeId = 2, TypeCode = "BUS", TypeDecription = "General Business, Commercial, Industrial" },
                    new AccountType() { AccountTypeId = 5, TypeCode = "UUO", TypeDecription = "Unidentified or Unclassified Type of Organization" },
                    new AccountType() { AccountTypeId = 4, TypeCode = "SGO", TypeDecription = "Social/Government/Non-Profit Organization, Institutional" },
                    new AccountType() { AccountTypeId = 6, TypeCode = "WAT", TypeDecription = "Water Intensive Business (Agricultural, Laudromat, Hair Salon, Restaurant, etc" }
                };
    
                string strAccountsTypes       = string.Empty;
                string fileAccountsTypes      = @"C:\Stellar Water Point2\AccountsTypes.json";
    
                JsonSerializerOptions options = new JsonSerializerOptions();
                options.WriteIndented         = true;
    
                FileInfo fiAccountsTypes      = new FileInfo(fileAccountsTypes);
                string jsAccountsTypes        = JsonSerializer.Serialize(types, typeof(List<AccountType>), options);
                File.WriteAllText(fiAccountsTypes.FullName, jsAccountsTypes);
            }
    
            public WaterDistribution()
            {
                InitializeComponent();
    
                CreateWaterMeters();
                CreateAccountsTypes();
            }
    
            private void WaterDistribution_Load(object sender, EventArgs e)
            {
                Directory.CreateDirectory(@"C:\Stellar Water Point2");
            }
    
            private void btnWaterMeters_Click(object sender, EventArgs e)
            {
                WaterMeters.Central central = new WaterMeters.Central();
    
                central.Show();
            }
        }
    }
  29. To execute the application, on the main menu, click Debug -> Start Without Debugging
  30. Close the forms and return to your programming environment
  31. Change theWaterDistribution.cs document as follows:
    using StellarWaterPoint2.Models;
    using System.Reflection.Metadata;
    using System.Text.Json;
    
    namespace StellarWaterPoint2
    {
        public partial class WaterDistribution : Form
        {
            private void CreateWaterMeters()
            {
                . . .
            }
    
            private void CreateAccountsTypes()
            {
                . . .
            }
    
            public WaterDistribution()
            {
                InitializeComponent();
    
                // CreateWaterMeters();
                // CreateAccountsTypes();
            }
    
            private void WaterDistribution_Load(object sender, EventArgs e)
            {
                Directory.CreateDirectory(@"C:\Stellar Water Point2");
            }
    
            private void btnWaterMeters_Click(object sender, EventArgs e)
            {
                WaterMeters.Central central = new WaterMeters.Central();
    
                central.Show();
            }
        }
    }

Customers

Introduction

For a water distribution company, a customer is a person, a business, or any entity that consumes water. At a minimum, a computer must keep a list of entities that use its business.

Practical LearningPractical Learning: Introducing Customers

  1. To create a class, in the Solution Explorer, right-click Models -> Add -> Class...
  2. On the main menu, click Project -> Add Class...
  3. Replace the name with AccountType
  4. Click Add
  5. Change the code as follows:
    namespace StellarWaterPoint2.Models
    {
        internal readonly record struct AccountType
        {
            public readonly int     AccountTypeId  { get; init; }
            public readonly string? TypeCode       { get; init; }
            public readonly string? TypeDecription { get; init; }
        }
    }
  6. To create a class, in the Solution Explorer, right-click Models -> Add -> Class...
  7. On the main menu, click Project -> Add Class...
  8. Replace the name with Customer
  9. Click Add
  10. Change the code as follows:
    namespace StellarWaterPoint2.Models
    {
        public class Customer
        {
            public int     CustomerId    { get; set; }
            public string? AccountNumber { get; set; }
            public string? AccountName   { get; set; }
            public string? MeterNumber   { get; set; }
            public string? AccountType   { get; set; }
            public string? Address       { get; set; }
            public string? City          { get; set; }
            public string? County        { get; set; }
            public string? State         { get; set; }
            public string? ZIPCode       { get; set; }
        }
    }
  11. To create a folder, in the Solution Explorer, right-click the StellarWaterPoint2 project -> Add -> New Folder
  12. Type Customers as the name of the folder

Displaying Customers

In a later section, we will learn how to create a customer record. When those records exist, a user can display them. We are going to make it possible through a form equipped with a list view

Practical LearningPractical Learning: Displaying Customers

  1. To create a form, in the Solution Explorer, right-click Customers -> Add -> Form (Windows Forms)...
  2. For 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 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
  7. Click OK
  8. Position and resize the list view on the form as follows:

    Stellar Water Point - Customers

    Control (Name) Other Properties
    ListView List View lvwCustomers FullRowSelect: True
    GridLines: True
    View: Details
  9. Double-click an unoccupied area of the form to generate its Load event
  10. Change the document as follows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.Customers
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowCustomers()
            {
                string strCustomers = string.Empty;
                List<Customer> Customers = new List<Customer>();
                string fileCustomers = @"C:\Stellar Water Point2\Customers.json";
    
                FileInfo fiCustomers = new FileInfo(fileCustomers);
    
                string strAccountsTypes = string.Empty;
                List<AccountType> accountsTypes = new List<AccountType>();
                string fileAccountsTypes = @"C:\Stellar Water Point2\AccountsTypes.json";
    
                FileInfo fiAccountsTypes = new FileInfo(fileAccountsTypes);
    
                if (fiCustomers.Exists == true)
                {
                    using (TextReader trCustomers = new StreamReader(fiCustomers.FullName))
                    {
                        strCustomers = File.ReadAllText(fiCustomers.FullName);
                        Customers = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
    
                        lvwCustomers.Items.Clear();
    
                        foreach (Customer wm in Customers)
                        {
                            ListViewItem lviCustomer = new ListViewItem(wm.CustomerId.ToString());
    
                            lviCustomer.SubItems.Add(wm.AccountNumber);
                            lviCustomer.SubItems.Add(wm.AccountName);
                            lviCustomer.SubItems.Add(wm.MeterNumber);
    
                            TextReader trAccountsTypess = new StreamReader(fiAccountsTypes.FullName);
                            strAccountsTypes = File.ReadAllText(fiAccountsTypes.FullName);
                            accountsTypes = JsonSerializer.Deserialize<List<AccountType>>(strAccountsTypes)!;
    
                            foreach (AccountType at in accountsTypes)
                            {
                                if (wm.AccountType == at.TypeCode)
                                {
                                    lviCustomer.SubItems.Add(string.Concat(at.TypeCode, " - ", at.TypeDecription));
                                }
                            }
                            
                            lviCustomer.SubItems.Add(wm.Address);
                            lviCustomer.SubItems.Add(wm.City);
                            lviCustomer.SubItems.Add(wm.County);
                            lviCustomer.SubItems.Add(wm.State);
                            lviCustomer.SubItems.Add(wm.ZIPCode);
                            lvwCustomers.Items.Add(lviCustomer);
                        }
                    }
                }
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                ShowCustomers();
            }
        }
    }
  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 btnCustomers C&ustomers... Times New Roman, 24pt, style=Bold
  14. Double-click the C&ustomers
  15. Impliment the event as follows:
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2
    {
        public partial class WaterDistribution : Form
        {
            public WaterDistribution()
            {
                InitializeComponent();
            }
    
            private void WaterDistribution_Load(object sender, EventArgs e)
            {
                Directory.CreateDirectory(@"C:\Stellar Water Point2");
    
                // Repository.CreateAccountsTypes();
                // Repository.CreateWaterMeters();
            }
    
            private void btnCustomers_Click(object sender, EventArgs e)
            {
                Customers.Central central = new();
    
                central.Show();
            }
    
            private void btnWaterMeters_Click(object sender, EventArgs e)
            {
                WaterMeters.Central central = new();
    
                central.Show();
            }
        }
    }

A New Customer Account

To use the services of a water distribution company, a customer must have an account. We are going to create a form that an employee can use to establish an account for a new customer.

Practical LearningPractical Learning: Creating a Customer Account

  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 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  
    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
    Label Label   Customer Id:&  
    TextBox Text Box txtCustomerId    
    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 - Create Customer Account
    StartPosition:   CenterScreen
    AcceptButton:    btnSaveCustomerAccount
    CancelButton:    btnCancel
  6. Double-click an unoccupied area of the form to generate its Load event
  7. Change the document as follows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.Customers
    {
        public partial class Create : Form
        {
            public Create()
            {
                InitializeComponent();
            }
    
            private void SetCustomerId()
            {
                string strCustomers = string.Empty;
                List<Customer> Customers = new List<Customer>();
                string fileCustomers = @"C:\Stellar Water Point2\Customers.json";
    
                FileInfo fiCustomers = new FileInfo(fileCustomers);
    
                int CustomerId = 0;
    
                if (fiCustomers.Exists == true)
                {
    
                    using (TextReader trCustomers = new StreamReader(fiCustomers.FullName))
                    {
                        strCustomers = File.ReadAllText(fiCustomers.FullName);
                        Customers = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
    
                        foreach (Customer wm in Customers)
                        {
                            CustomerId = wm.CustomerId;
                        }
                    }
                }
    
                txtCustomerId.Text = (CustomerId + 1).ToString();
            }
    
            private void SetAccountsTypes()
            {
                string strAccountsTypes = string.Empty;
                List<AccountType> types = new List<AccountType>();
                string fileAccountsTypes = @"C:\Stellar Water Point2\AccountsTypes.json";
    
                FileInfo fiAccountsTypes = new FileInfo(fileAccountsTypes);
    
                if (fiAccountsTypes.Exists == true)
                {
                    strAccountsTypes = File.ReadAllText(fiAccountsTypes.FullName);
                    types = JsonSerializer.Deserialize<List<AccountType>>(strAccountsTypes)!;
    
                    foreach (AccountType type in types)
                    {
                        cbxAccountsTypes.Items.Add(type.TypeCode + " - " + type.TypeDecription);
                    }
                }
            }
    
            private void Create_Load(object sender, EventArgs e)
            {
                SetCustomerId();
                SetAccountsTypes();
            }
            
        }
    }
  8. Return to the form and double-click the Find Water Meter button
  9. Implement the event as tollows:
    private void btnFindWaterMeter_Click(object sender, EventArgs e)
    {
        if (mtbMeterNumber.Text.Replace("-", "").Trim().Equals(string.Empty))
        {
            MsgBox.Show("You must type a valid meter number, " +
                        "and then click the Find Water Meter button.");
            return;
        }
    
        string strWaterMeters = string.Empty;
        List<WaterMeter> waterMeters = new List<WaterMeter>();
        string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
        FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
        if (fiWaterMeters.Exists == true)
        {
            strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
            waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
    
            foreach (WaterMeter meter in waterMeters)
            {
                if (meter.MeterNumber == mtbMeterNumber.Text)
                {
                    txtMeterDetails.Text = meter.WaterMeterId.ToString() + " - " +
                                           meter.Make + " " +
                                           meter.Model +
                                           " (Meter Size: " + meter.MeterSize + ")";
                }
            }
        }
    }
  10. In the Solution Explorer, below the Customers folder, double-click Central.cs
  11. From the Toolbox, add a button to the form below the list view
  12. Change the characteristics of the button as follows:

    Stellar Water Point - Water Meters

    Control (Name) Other Properties
    ListView List View lvwCustomers FullRowSelect: True
    GridLines: True
    View: Details
    Button Button btnNewCustomerAccount &New Customer Account...
  13. On the Central form, double-click the New Customer Account button
  14. Implement the event as follows:
    private void btnCreateCustomerAccount_Click(object sender, EventArgs e)
    {
        Create create = new();
    
        if (create.ShowDialog() == DialogResult.OK)
        {
            if(create.mtbAccountNumber.Text.Replace("-", "").Trim().Equals(""))
            {
                MsgBox.Show("You must provide an account number for a new customer. " +
                                "Otherwise, the account cannot be created.");
                return;
            }
    
            if (create.mtbMeterNumber.Text.Replace("-", "").Trim().Equals(string.Empty))
            {
                MsgBox.Show("You must type a valid meter number to associate " +
                            "a water meter to a customer's account. After providing " +
                            "a meter number, click the Find Water Meter button.");
                return;
            }
    
            string strCustomers = string.Empty;
            List<Customer> clients = new List<Customer>();
            string fileCustomers = @"C:\Stellar Water Point2\Customers.json";
    
            FileInfo fiCustomers = new FileInfo(fileCustomers);
    
            if (fiCustomers.Exists == true)
            {
                strCustomers = File.ReadAllText(fiCustomers.FullName);
                clients = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
            }
    
            Customer client = new Customer()
            {
                CustomerId = int.Parse(create.txtCustomerId.Text),
                AccountNumber = create.mtbAccountNumber.Text,
                AccountName = create.txtAccountName.Text,
                MeterNumber = create.mtbMeterNumber.Text,
                AccountType = create.cbxAccountsTypes.Text.Substring(0, 3),
                Address = create.txtAddress.Text,
                City = create.txtCity.Text,
                County = create.txtCounty.Text,
                State = create.txtState.Text,
                ZIPCode = create.mtbZIPCode.Text
            };
    
            clients.Add(client);
    
            JsonSerializerOptions options = new JsonSerializerOptions();
            options.WriteIndented = true;
    
            string jsCustomers = JsonSerializer.Serialize(clients, typeof(List<Customer>), options);
            File.WriteAllText(fiCustomers.FullName, jsCustomers);
        }
    
        ShowCustomers();
    }
  15. To execute the application, on the main menu, click Debug -> Start Without Debugging:

    Stellar Water Point - New Customer Account

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

    Stellar Water Point - Customers Accounts

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

    Stellar Water Point - Customers Accounts

  18. In the account # text box, type 9279-570-8394
  19. In the meter # text box, type 799-528-461
  20. Click the Find water meter button
  21. 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

  22. Click Save Customer Account
  23. 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

  24. Close the forms and return to your programming environment

Customer Account Details

When a customer account has been created, at any time, an employee may want to simply review such an account. Our application needs a form for that.

Practical LearningPractical Learning: Showing Customer Account

  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 &Details:  
    TextBox Text Box txtMeterDetails   Enabled: False
    Label Label   &Account Type:  
    TextBox Combo Box txtAccountsTypes   Enabled: False
    Label Label   &Address:  
    TextBox Text Box txtAddress   Enabled: False
    Label Label   C&ity:  
    TextBox Text Box txtCity   Enabled: False
    Label Label   C&ounty:  
    TextBox Text Box txtCounty   Enabled: False
    Label Label   &State:  
    TextBox Text Box txtState   Enabled: False
    Label Label   &ZIP-Code:  
    TextBox Masked Text Box txtZIPCode   Enabled: False
    Label Label   Customer Id:&:  
    TextBox Text Box txtCustomerId   Enabled: False
    Button Button btnClose &Close  
  5. On the form, double-click the Find Customer Account button
  6. Change the document as follows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.Customers
    {
        public partial class Details : Form
        {
            public Details()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                if (mtbAccountNumber.Text.Replace("-", "").Trim() == "")
                {
                    MsgBox.Show("You must type a valid account number of a customer, " +
                                    "and then click the Find Customer Account button.");
                    return;
                }
    
                string strCustomers = string.Empty;
                string strAccountType = string.Empty;
                List<Customer> clients = new List<Customer>();
                string fileCustomers = @"C:\Stellar Water Point2\Customers.json";
    
                FileInfo fiCustomers = new FileInfo(fileCustomers);
    
                string? strMeterNumber = string.Empty;
    
                if (fiCustomers.Exists == true)
                {
                    using (TextReader trCustomers = new StreamReader(fiCustomers.FullName))
                    {
                        strCustomers = File.ReadAllText(fiCustomers.FullName);
                        clients = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
    
                        IEnumerable<Customer> customers = from consumer
                                                          in clients
                                                          where consumer.AccountNumber == mtbAccountNumber.Text
                                                          select consumer;
    
                        foreach (Customer client in customers)
                        {
                            txtCustomerId.Text = client.CustomerId.ToString();
                            txtAccountName.Text = client.AccountName;
                            strMeterNumber = client.MeterNumber;
                            strAccountType = client.AccountType!;
                            txtAddress.Text = client.Address;
                            txtCity.Text = client.City;
                            txtCounty.Text = client.County;
                            txtState.Text = client.State;
                            txtZIPCode.Text = client.ZIPCode;
                        }
                    }
                }
    
                if (strMeterNumber!.Length > 0)
                {
                    string strWaterMeters = string.Empty;
                    List<WaterMeter> waterMeters = new List<WaterMeter>();
                    string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
                    FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
                    if (fiWaterMeters.Exists == true)
                    {
                        strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
                        waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
    
                        IEnumerable<WaterMeter> meters = from measure
                                                         in waterMeters
                                                         where measure.MeterNumber == strMeterNumber
                                                         select measure;
    
                        foreach (WaterMeter meter in waterMeters)
                        {
                            txtMeterDetails.Text = meter.Make + " " +
                                                   meter.Model +
                                                   " (Meter Size: " + meter.MeterSize + ")";
                        }
                    }
                }
    
                string strAccountsTypes = string.Empty;
                List<AccountType> types = new List<AccountType>();
                string fileAccountsTypes = @"C:\Stellar Water Point2\AccountsTypes.json";
    
                FileInfo fiAccountsTypes = new FileInfo(fileAccountsTypes);
    
                if (fiAccountsTypes.Exists == true)
                {
                    strAccountsTypes = File.ReadAllText(fiAccountsTypes.FullName);
                    types = JsonSerializer.Deserialize<List<AccountType>>(strAccountsTypes)!;
    
                    IEnumerable<AccountType> actType = from category
                                                       in types
                                                       where category.TypeCode == strAccountType
                                                       select category;
    
                    
                    foreach (AccountType type in types)
                    {
                        txtAccountType.Text = $"{type.TypeCode } - {type.TypeDecription}";
                    }
                }
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  7. Return to the form and double-click the Close button
  8. Change the document as follows:
    private void btnClose_Click(object sender, EventArgs e)
    {
        Close();
    }
  9. In the Solution Explorer, below the Customers folder, double-click Central.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 New Customer Account button
  11. Change the characteristics of the button as follows:

    Stellar Water Point - Customer Account Details

    Control (Name) Other Properties
    ListView List View lvwCustomers No Change
    Button Button No Change No Change
    Button Button btnCustomerAccountDetails Customer Account &Details...
  12. Double-click the Customer Account &Details button
  13. Change the document as follows:
    using System.Data;
    using Microsoft.Data.SqlClient;
    
    namespace StellarWaterPoint2.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 btnCustomerAccountDetails_Click(object sender, EventArgs e)
            {
                Details details = new();
    
                details.ShowDialog();
    
                ShowCustomers();
            }
        }
    }
  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 Customers button
  16. On the Central form of the customers form, click the Customer Account &Details button:

    Stellar Water Point - View Water Meter

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

    Stellar Water Point - View Water Meter

  19. Close the forms and return to your programming environment

Editing a Customer Account

When a piece of information has changed about a customer, an employee should update the customer account. We will provide a for such an operation.

Practical LearningPractical Learning: Editing a Customer Account

  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. Design the form as follows:

    Stellar Water Point - Customer Account Editor

    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    
    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  
    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
    Label Label   Customer Id:&:  
    TextBox Text Box txtCustomerId   Enabled: False
    Button Button btnUpdateCustomerAccount &Update Customer Account DialogResult: OK
    Button Button btnClose &Close DialogResult: Cancel
  5. Double-click an unoccupied area of the form to generate its Load event
  6. Change the document as follows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.Customers
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void Editor_Load(object sender, EventArgs e)
            {
                string strAccountsTypes = string.Empty;
                List<AccountType> types = new List<AccountType>();
                string fileAccountsTypes = @"C:\Stellar Water Point2\AccountsTypes.json";
    
                FileInfo fiAccountsTypes = new FileInfo(fileAccountsTypes);
    
                if (fiAccountsTypes.Exists == true)
                {
                    strAccountsTypes = File.ReadAllText(fiAccountsTypes.FullName);
                    types = JsonSerializer.Deserialize<List<AccountType>>(strAccountsTypes)!;
    
                    foreach (AccountType type in types)
                    {
                        cbxAccountsTypes.Items.Add(type.TypeCode + " - " + type.TypeDecription);
                    }
                }
            }
        }
    }
  7. Return to the form, double-click the Find Customer Account button
  8. Change the document as follows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.Customers
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void Editor_Load(object sender, EventArgs e)
            {
                . . .
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                if (mtbAccountNumber.Text.Replace("-", "").Trim() == "")
                {
                    MsgBox.Show("You must type a valid account number of a customer, " +
                                    "and then click the Find Customer Account button.");
                    return;
                }
    
                string strCustomers = string.Empty;
                string strAccountType = string.Empty;
                List<Customer> clients = new List<Customer>();
                string fileCustomers = @"C:\Stellar Water Point2\Customers.json";
    
                FileInfo fiCustomers = new FileInfo(fileCustomers);
    
                if (fiCustomers.Exists == true)
                {
                    using (TextReader trCustomers = new StreamReader(fiCustomers.FullName))
                    {
                        strCustomers = File.ReadAllText(fiCustomers.FullName);
                        clients = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
    
                        IEnumerable<Customer> customers = from consumer
                                                          in clients
                                                          where consumer.AccountNumber == mtbAccountNumber.Text
                                                          select consumer;
    
                        foreach (Customer client in customers)
                        {
                            txtCustomerId.Text = client.CustomerId.ToString();
                            txtAccountName.Text = client.AccountName;
                            mtbMeterNumber.Text = client.MeterNumber;
                            strAccountType = client.AccountType!;
                            txtAddress.Text = client.Address;
                            txtCity.Text = client.City;
                            txtCounty.Text = client.County;
                            txtState.Text = client.State;
                            mtbZIPCode.Text = client.ZIPCode;
                        }
                    }
                }
    
                if (mtbAccountNumber.Text!.Length > 0)
                {
                    string strWaterMeters = string.Empty;
                    List<WaterMeter> waterMeters = new List<WaterMeter>();
                    string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
                    FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
                    if (fiWaterMeters.Exists == true)
                    {
                        strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
                        waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
    
                        IEnumerable<WaterMeter> meters = from measure
                                                         in waterMeters
                                                         where measure.MeterNumber == mtbMeterNumber.Text
                                                         select measure;
    
                        foreach (WaterMeter meter in waterMeters)
                        {
                            txtMeterDetails.Text = meter.Make + " " +
                                                   meter.Model +
                                                   " (Meter Size: " + meter.MeterSize + ")";
                        }
                    }
                }
    
                string strAccountsTypes = string.Empty;
                List<AccountType> types = new List<AccountType>();
                string fileAccountsTypes = @"C:\Stellar Water Point2\AccountsTypes.json";
    
                FileInfo fiAccountsTypes = new FileInfo(fileAccountsTypes);
    
                if (fiAccountsTypes.Exists == true)
                {
                    strAccountsTypes = File.ReadAllText(fiAccountsTypes.FullName);
                    types = JsonSerializer.Deserialize<List<AccountType>>(strAccountsTypes)!;
    
                    IEnumerable<AccountType> actType = from category
                                                       in types
                                                       where category.TypeCode == strAccountType
                                                       select category;
    
    
                    foreach (AccountType type in types)
                    {
                        cbxAccountsTypes.Text = $"{type.TypeCode} - {type.TypeDecription}";
                    }
                }
            }
        }
    }
  9. Return to the form and double-click the Find Water Meter button
  10. Change the document as follows:
    private void btnFindWaterMeter_Click(object sender, EventArgs e)
    {
        if (mtbMeterNumber.Text.Replace("-", "").Trim().Equals(string.Empty))
        {
            MsgBox.Show("You must type a valid meter number, " +
                        "and then click the Find Water Meter button.");
            return;
        }
    
        string strWaterMeters = string.Empty;
        List<WaterMeter> waterMeters = new List<WaterMeter>();
        string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
        FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
        if (fiWaterMeters.Exists == true)
        {
            strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
            waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
    
            foreach (WaterMeter meter in waterMeters)
            {
                if (meter.MeterNumber == mtbMeterNumber.Text)
                {
                    txtMeterDetails.Text = meter.Make + " " +
                                           meter.Model +
                                           " (Meter Size: " + meter.MeterSize + ")";
                }
            }
        }
    }
  11. Return to the form and double-click the Update Water Meter button
  12. Change the document as follows:
    private void btnUpdateCustomerAccount_Click(object sender, EventArgs e)
    {
        if (string.IsNullOrEmpty(mtbAccountNumber.Text))
        {
            MsgBox.Show("Please enter an account number for a customer. " +
                        "You can then click the Find Customer Account button " +
                        "to indicate the customer whose account you want o update.");
            return;
        }
    
        if (string.IsNullOrEmpty(mtbMeterNumber.Text))
        {
            MsgBox.Show("You must type a valid meter number, " +
                        "and then click the Find Water Meter button.");
            return;
        }
    
        string strCustomers    = string.Empty;
        List<Customer> clients = new List<Customer>();
        string fileCustomers   = @"C:\Stellar Water Point2\Customers.json";
    
        FileInfo fiCustomers   = new FileInfo(fileCustomers);
    
        if (fiCustomers.Exists == true)
        {
            strCustomers       = File.ReadAllText(fiCustomers.FullName);
            clients = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
    
            Customer? customer = clients.Find(cust => cust.AccountNumber == mtbAccountNumber.Text);
    
            if (customer is not null)
            {
                customer.CustomerId    = int.Parse(txtCustomerId.Text);
                customer.AccountNumber = mtbAccountNumber.Text;
                customer.AccountName   = txtAccountName.Text;
                customer.MeterNumber   = mtbMeterNumber.Text;
                customer.AccountType   = cbxAccountsTypes.Text.Substring(0, 3);
                customer.Address       = txtAddress.Text;
                customer.City          = txtCity.Text;
                customer.County        = txtCounty.Text;
                customer.State         = txtState.Text;
                customer.ZIPCode       = mtbZIPCode.Text;
    
                JsonSerializerOptions options = new JsonSerializerOptions();
                options.WriteIndented = true;
    
                string jsCustomers = JsonSerializer.Serialize(clients, typeof(List<Customer>), options);
                File.WriteAllText(fiCustomers.FullName, jsCustomers);
            }
        }
    
        Close();
    }
  13. Return to the form and double-click the Close button
  14. Change the document as follows:
    using StellarWaterPoint2.Models;
    using System.Diagnostics.Metrics;
    using System.Net;
    using System.Reflection.Emit;
    using System.Text.Json;
    using static System.Windows.Forms.AxHost;
    
    namespace StellarWaterPoint2.Customers
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void Editor_Load(object sender, EventArgs e)
            {
                string strAccountsTypes = string.Empty;
                List<AccountType> types = new List<AccountType>();
                string fileAccountsTypes = @"C:\Stellar Water Point2\AccountsTypes.json";
    
                FileInfo fiAccountsTypes = new FileInfo(fileAccountsTypes);
    
                if (fiAccountsTypes.Exists == true)
                {
                    strAccountsTypes = File.ReadAllText(fiAccountsTypes.FullName);
                    types = JsonSerializer.Deserialize<List<AccountType>>(strAccountsTypes)!;
    
                    foreach (AccountType type in types)
                    {
                        cbxAccountsTypes.Items.Add(type.TypeCode + " - " + type.TypeDecription);
                    }
                }
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                if (mtbAccountNumber.Text.Replace("-", "").Trim() == "")
                {
                    MsgBox.Show("You must type a valid account number of a customer, " +
                                    "and then click the Find Customer Account button.");
                    return;
                }
    
                string strCustomers = string.Empty;
                string strAccountType = string.Empty;
                List<Customer> clients = new List<Customer>();
                string fileCustomers = @"C:\Stellar Water Point2\Customers.json";
    
                FileInfo fiCustomers = new FileInfo(fileCustomers);
    
                if (fiCustomers.Exists == true)
                {
                    using (TextReader trCustomers = new StreamReader(fiCustomers.FullName))
                    {
                        strCustomers = File.ReadAllText(fiCustomers.FullName);
                        clients = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
    
                        IEnumerable<Customer> customers = from consumer
                                                          in clients
                                                          where consumer.AccountNumber == mtbAccountNumber.Text
                                                          select consumer;
    
                        foreach (Customer client in customers)
                        {
                            txtCustomerId.Text = client.CustomerId.ToString();
                            txtAccountName.Text = client.AccountName;
                            mtbMeterNumber.Text = client.MeterNumber;
                            strAccountType = client.AccountType!;
                            txtAddress.Text = client.Address;
                            txtCity.Text = client.City;
                            txtCounty.Text = client.County;
                            txtState.Text = client.State;
                            mtbZIPCode.Text = client.ZIPCode;
                        }
                    }
                }
    
                if (mtbAccountNumber.Text!.Length > 0)
                {
                    string strWaterMeters = string.Empty;
                    List<WaterMeter> waterMeters = new List<WaterMeter>();
                    string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
                    FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
                    if (fiWaterMeters.Exists == true)
                    {
                        strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
                        waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
    
                        IEnumerable<WaterMeter> meters = from measure
                                                         in waterMeters
                                                         where measure.MeterNumber == mtbMeterNumber.Text
                                                         select measure;
    
                        foreach (WaterMeter meter in waterMeters)
                        {
                            txtMeterDetails.Text = meter.Make + " " +
                                                   meter.Model +
                                                   " (Meter Size: " + meter.MeterSize + ")";
                        }
                    }
                }
    
                string strAccountsTypes = string.Empty;
                List<AccountType> types = new List<AccountType>();
                string fileAccountsTypes = @"C:\Stellar Water Point2\AccountsTypes.json";
    
                FileInfo fiAccountsTypes = new FileInfo(fileAccountsTypes);
    
                if (fiAccountsTypes.Exists == true)
                {
                    strAccountsTypes = File.ReadAllText(fiAccountsTypes.FullName);
                    types = JsonSerializer.Deserialize<List<AccountType>>(strAccountsTypes)!;
    
                    IEnumerable<AccountType> actType = from category
                                                       in types
                                                       where category.TypeCode == strAccountType
                                                       select category;
    
    
                    foreach (AccountType type in types)
                    {
                        cbxAccountsTypes.Text = $"{type.TypeCode} - {type.TypeDecription}";
                    }
                }
            }
    
            private void btnFindWaterMeter_Click(object sender, EventArgs e)
            {
                if (mtbMeterNumber.Text.Replace("-", "").Trim().Equals(string.Empty))
                {
                    MsgBox.Show("You must type a valid meter number, " +
                                "and then click the Find Water Meter button.");
                    return;
                }
    
                string strWaterMeters = string.Empty;
                List<WaterMeter> waterMeters = new List<WaterMeter>();
                string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
                FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
                if (fiWaterMeters.Exists == true)
                {
                    strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
                    waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
    
                    foreach (WaterMeter meter in waterMeters)
                    {
                        if (meter.MeterNumber == mtbMeterNumber.Text)
                        {
                            txtMeterDetails.Text = meter.Make + " " +
                                                   meter.Model +
                                                   " (Meter Size: " + meter.MeterSize + ")";
                        }
                    }
                }
            }
    
            private void btnUpdateCustomerAccount_Click(object sender, EventArgs e)
            {
                if (string.IsNullOrEmpty(mtbAccountNumber.Text))
                {
                    MsgBox.Show("Please enter an account number for a customer. " +
                                "You can then click the Find Customer Account button " +
                                "to indicate the customer whose account you want o update.");
                    return;
                }
    
                if (string.IsNullOrEmpty(mtbMeterNumber.Text))
                {
                    MsgBox.Show("You must type a valid meter number, " +
                                "and then click the Find Water Meter button.");
                    return;
                }
    
                string strCustomers    = string.Empty;
                List<Customer> clients = new List<Customer>();
                string fileCustomers   = @"C:\Stellar Water Point2\Customers.json";
    
                FileInfo fiCustomers   = new FileInfo(fileCustomers);
    
                if (fiCustomers.Exists == true)
                {
                    strCustomers       = File.ReadAllText(fiCustomers.FullName);
                    clients = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
    
                    Customer? customer = clients.Find(cust => cust.AccountNumber == mtbAccountNumber.Text);
    
                    if (customer is not null)
                    {
                        customer.CustomerId    = int.Parse(txtCustomerId.Text);
                        customer.AccountNumber = mtbAccountNumber.Text;
                        customer.AccountName   = txtAccountName.Text;
                        customer.MeterNumber   = mtbMeterNumber.Text;
                        customer.AccountType   = cbxAccountsTypes.Text.Substring(0, 3);
                        customer.Address       = txtAddress.Text;
                        customer.City          = txtCity.Text;
                        customer.County        = txtCounty.Text;
                        customer.State         = txtState.Text;
                        customer.ZIPCode       = mtbZIPCode.Text;
    
                        JsonSerializerOptions options = new JsonSerializerOptions();
                        options.WriteIndented = true;
    
                        string jsCustomers = JsonSerializer.Serialize(clients, typeof(List<Customer>), options);
                        File.WriteAllText(fiCustomers.FullName, jsCustomers);
                    }
                }
    
                Close();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  15. In the Solution Explorer, below the Customers folder, double-click Central.cs
  16. From the Toolbox, add a button to the form below the list view and on the right side of the Customer Account Editor button
  17. Change the characteristics of the button as follows:

    Stellar Water Point - Water Meters

    Control (Name) Other Properties
    ListView List View lvwCustomers No Change
    Button Button btnNewCustomerAccount No Change
    Button Button btnCustomerAccountDetails No Change
    Button Button btnUpdateCustomerAccount &Update Customer Account...
  18. Display the Central form of the Customers folder
  19. Double-click the Update Customer Account button
  20. Change the document as follows:
    using System.Data;
    using Microsoft.Data.SqlClient;
    
    namespace StellarWaterPoint2.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 btnCustomerAccountDetails_Click(object sender, EventArgs e)
            {
                Details details = new();
    
                details.ShowDialog();
    
                ShowCustomers();
            }
    
            private void btnEditCustomerAccount_Click(object sender, EventArgs e)
            {
                Editor editor = new();
    
                editor.ShowDialog();
    
                ShowCustomers();
            }
        }
    }
  21. To execute the application, on the main menu, click Debug -> Start Without Debugging

    Stellar Water Point

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

    Stellar Water Point - Customers

  23. Click the Edit Customer Account button:

    Stellar Water Point - Customer Account Editor

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

    Stellar Water Point - Customer Account Editor

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

    Stellar Water Point - Customer Account Editor

  27. Click the Update Customer Account button:

    Stellar Water Point - Customers Accounts

  28. Close the forms and return to your programming environment

Deleting a Customer Account from the Database

If an employee realizes that a customer account must not exist anymore, the employee can delete that account. We will provide a form for such an operation.

Practical LearningPractical Learning: Deleting a Customer Account

  1. To create a form, in the Solution Explorer, right-click Customers -> 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. Design the form as follows:

    Stellar Water Point - Customer Account Deletion

    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 &Details:  
    TextBox Text Box txtMeterDetails   Enabled: False
    Label Label   &Account Type:  
    TextBox Combo Box txtAccountsTypes   Enabled: False
    Label Label   &Address:  
    TextBox Text Box txtAddress   Enabled: False
    Label Label   C&ity:  
    TextBox Text Box txtCity   Enabled: False
    Label Label   C&ounty:  
    TextBox Text Box txtCounty   Enabled: False
    Label Label   &State:  
    TextBox Text Box txtState   Enabled: False
    Label Label   &ZIP-Code:  
    TextBox Masked Text Box txtZIPCode   Enabled: False
    Button Button btnDeleteCustomerAccount &Delete Customer Account  
    Button Button btnClose &Close  
  5. On the form, double-click the Find Customer Account button
  6. Change the document as tollows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.Customers
    {
        public partial class Delete : Form
        {
            public Delete()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                if (mtbAccountNumber.Text.Replace("-", "").Trim() == "")
                {
                    MsgBox.Show("You must type a valid account number of a customer, " +
                                    "and then click the Find Customer Account button.");
                    return;
                }
    
                string strCustomers = string.Empty;
                string strAccountType = string.Empty;
                List<Customer> clients = new List<Customer>();
                string fileCustomers = @"C:\Stellar Water Point2\Customers.json";
    
                FileInfo fiCustomers = new FileInfo(fileCustomers);
    
                string? strMeterNumber = string.Empty;
    
                if (fiCustomers.Exists == true)
                {
                    using (TextReader trCustomers = new StreamReader(fiCustomers.FullName))
                    {
                        strCustomers = File.ReadAllText(fiCustomers.FullName);
                        clients = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
    
                        IEnumerable<Customer> customers = from consumer
                                                          in clients
                                                          where consumer.AccountNumber == mtbAccountNumber.Text
                                                          select consumer;
    
                        foreach (Customer client in customers)
                        {
                            txtCustomerId.Text = client.CustomerId.ToString();
                            txtAccountName.Text = client.AccountName;
                            strMeterNumber = client.MeterNumber;
                            strAccountType = client.AccountType!;
                            txtAddress.Text = client.Address;
                            txtCity.Text = client.City;
                            txtCounty.Text = client.County;
                            txtState.Text = client.State;
                            txtZIPCode.Text = client.ZIPCode;
                        }
                    }
                }
    
                if (strMeterNumber!.Length > 0)
                {
                    string strWaterMeters = string.Empty;
                    List<WaterMeter> waterMeters = new List<WaterMeter>();
                    string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
                    FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
                    if (fiWaterMeters.Exists == true)
                    {
                        strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
                        waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
    
                        IEnumerable<WaterMeter> meters = from measure
                                                         in waterMeters
                                                         where measure.MeterNumber == strMeterNumber
                                                         select measure;
    
                        foreach (WaterMeter meter in waterMeters)
                        {
                            txtMeterDetails.Text = meter.Make + " " +
                                                   meter.Model +
                                                   " (Meter Size: " + meter.MeterSize + ")";
                        }
                    }
                }
    
                string strAccountsTypes = string.Empty;
                List<AccountType> types = new List<AccountType>();
                string fileAccountsTypes = @"C:\Stellar Water Point2\AccountsTypes.json";
    
                FileInfo fiAccountsTypes = new FileInfo(fileAccountsTypes);
    
                if (fiAccountsTypes.Exists == true)
                {
                    strAccountsTypes = File.ReadAllText(fiAccountsTypes.FullName);
                    types = JsonSerializer.Deserialize<List<AccountType>>(strAccountsTypes)!;
    
                    IEnumerable<AccountType> actType = from category
                                                       in types
                                                       where category.TypeCode == strAccountType
                                                       select category;
    
    
                    foreach (AccountType type in types)
                    {
                        txtAccountType.Text = $"{type.TypeCode} - {type.TypeDecription}";
                    }
                }
            }
        }
    }
  7. Return to the form and double-click the Delete Customer Account button
  8. Implement the event as tollows:
    private void btnDeleteCustomerAccount_Click(object sender, EventArgs e)
    {
        if (mtbAccountNumber.Text.Replace("-", "").Trim() == "")
        {
            MsgBox.Show("You must type a valid account number of a customer, " +
                            "and then click the Find Customer Account button. " +
                            "Only then can you delete an customer account.");
            return;
        }
    
        string strCustomers = string.Empty;
        List<Customer> clients = new List<Customer>();
        string fileCustomers = @"C:\Stellar Water Point2\Customers.json";
    
        FileInfo fiCustomers = new FileInfo(fileCustomers);
    
        if (fiCustomers.Exists == true)
        {
            strCustomers = File.ReadAllText(fiCustomers.FullName);
            clients = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
    
            Customer client = clients.Find(acnt => acnt.AccountNumber == mtbAccountNumber.Text)!;
    
            if (client is not null)
            {
                if (MsgBox.Question("Are you sure you want to delete this customer's account " +
                                    "(you cannot undo the action)?") == Answer.Yes)
                {
                    clients.Remove(client);
    
                    JsonSerializerOptions options = new JsonSerializerOptions();
                    options.WriteIndented = true;
    
                    string jsCustomers = JsonSerializer.Serialize(clients, typeof(List<Customer>), options);
                    File.WriteAllText(fiCustomers.FullName, jsCustomers);
    
                    MsgBox.Show("The customer's account has been deleted from our system.");
                }
            }
        }
    
        Close();
    }
  9. Return to the form and double-click the Close button
  10. Implement the event as tollows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.Customers
    {
        public partial class Delete : Form
        {
            public Delete()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                if (mtbAccountNumber.Text.Replace("-", "").Trim() == "")
                {
                    MsgBox.Show("You must type a valid account number of a customer, " +
                                    "and then click the Find Customer Account button.");
                    return;
                }
    
                string strCustomers = string.Empty;
                string strAccountType = string.Empty;
                List<Customer> clients = new List<Customer>();
                string fileCustomers = @"C:\Stellar Water Point2\Customers.json";
    
                FileInfo fiCustomers = new FileInfo(fileCustomers);
    
                string? strMeterNumber = string.Empty;
    
                if (fiCustomers.Exists == true)
                {
                    using (TextReader trCustomers = new StreamReader(fiCustomers.FullName))
                    {
                        strCustomers = File.ReadAllText(fiCustomers.FullName);
                        clients = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
    
                        IEnumerable<Customer> customers = from consumer
                                                          in clients
                                                          where consumer.AccountNumber == mtbAccountNumber.Text
                                                          select consumer;
    
                        foreach (Customer client in customers)
                        {
                            txtCustomerId.Text = client.CustomerId.ToString();
                            txtAccountName.Text = client.AccountName;
                            strMeterNumber = client.MeterNumber;
                            strAccountType = client.AccountType!;
                            txtAddress.Text = client.Address;
                            txtCity.Text = client.City;
                            txtCounty.Text = client.County;
                            txtState.Text = client.State;
                            txtZIPCode.Text = client.ZIPCode;
                        }
                    }
                }
    
                if (strMeterNumber!.Length > 0)
                {
                    string strWaterMeters = string.Empty;
                    List<WaterMeter> waterMeters = new List<WaterMeter>();
                    string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
                    FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
                    if (fiWaterMeters.Exists == true)
                    {
                        strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
                        waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
    
                        IEnumerable<WaterMeter> meters = from measure
                                                         in waterMeters
                                                         where measure.MeterNumber == strMeterNumber
                                                         select measure;
    
                        foreach (WaterMeter meter in waterMeters)
                        {
                            txtMeterDetails.Text = meter.Make + " " +
                                                   meter.Model +
                                                   " (Meter Size: " + meter.MeterSize + ")";
                        }
                    }
                }
    
                string strAccountsTypes = string.Empty;
                List<AccountType> types = new List<AccountType>();
                string fileAccountsTypes = @"C:\Stellar Water Point2\AccountsTypes.json";
    
                FileInfo fiAccountsTypes = new FileInfo(fileAccountsTypes);
    
                if (fiAccountsTypes.Exists == true)
                {
                    strAccountsTypes = File.ReadAllText(fiAccountsTypes.FullName);
                    types = JsonSerializer.Deserialize<List<AccountType>>(strAccountsTypes)!;
    
                    IEnumerable<AccountType> actType = from category
                                                       in types
                                                       where category.TypeCode == strAccountType
                                                       select category;
    
    
                    foreach (AccountType type in types)
                    {
                        txtAccountType.Text = $"{type.TypeCode} - {type.TypeDecription}";
                    }
                }
            }
    
            private void btnDeleteCustomerAccount_Click(object sender, EventArgs e)
            {
                if (mtbAccountNumber.Text.Replace("-", "").Trim() == "")
                {
                    MsgBox.Show("You must type a valid account number of a customer, " +
                                "and then click the Find Customer Account button. " +
                                "Only then can you delete an customer account.");
                    return;
                }
    
                string strCustomers = string.Empty;
                List<Customer> clients = new List<Customer>();
                string fileCustomers = @"C:\Stellar Water Point2\Customers.json";
    
                FileInfo fiCustomers = new FileInfo(fileCustomers);
    
                if (fiCustomers.Exists == true)
                {
                    strCustomers = File.ReadAllText(fiCustomers.FullName);
                    clients = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
    
                    Customer client = clients.Find(acnt => acnt.AccountNumber == mtbAccountNumber.Text)!;
    
                    if (client is not null)
                    {
                        if (MsgBox.Question("Are you sure you want to delete this customer's account " +
                                            "(you cannot undo the action)?") == Answer.Yes)
                        {
                            clients.Remove(client);
    
                            JsonSerializerOptions options = new JsonSerializerOptions();
                            options.WriteIndented = true;
    
                            string jsCustomers = JsonSerializer.Serialize(clients, typeof(List<Customer>), options);
                            File.WriteAllText(fiCustomers.FullName, jsCustomers);
    
                            MsgBox.Show("The customer's account has been deleted from our system.");
                        }
                    }
                }
    
                Close();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  11. In the Solution Explorer, below the Customers folder, double-click Central.cs
  12. From the Toolbox, add two buttons to the form below the list view and on the right side of the Update Customer Account button
  13. Change the characteristics of the buttons as follows:

    Stellar Water Point - Water Meters

    Control (Name) Other Properties
    ListView List View lvwCustomers FullRowSelect: True
    GridLines: True
    View: Details
    Anchor: Top, Bottom, Left, Right
    Button Button btnCreateCustomerAccount Create Customer &Account....
    Anchor: Bottom, Right
    Button Button btnCustomerAccountDetails Customer Account &Details...
    Anchor: Bottom, Right
    Button Button btnEditCustomerAccount &Edit Customer Account...
    Anchor: Bottom, Right
    Button Button btnDeleteCustomerAccount &Delete Customer Account...
    Anchor: Bottom, Right
    Button Button btnClose &Close
    Anchor: Bottom, Right
  14. On the form, double-click the Delete Customer Account button
  15. Return to the Central form of the water meters and double-click the Close button
  16. Change the document as follows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.Customers
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowCustomers()
            {
                string strCustomers = string.Empty;
                List<Customer> Customers = new List<Customer>();
                string fileCustomers = @"C:\Stellar Water Point2\Customers.json";
    
                FileInfo fiCustomers = new FileInfo(fileCustomers);
    
                string strAccountsTypes = string.Empty;
                List<AccountType> accountsTypes = new List<AccountType>();
                string fileAccountsTypes = @"C:\Stellar Water Point2\AccountsTypes.json";
    
                FileInfo fiAccountsTypes = new FileInfo(fileAccountsTypes);
    
                if (fiCustomers.Exists == true)
                {
                    using (TextReader trCustomers = new StreamReader(fiCustomers.FullName))
                    {
                        strCustomers = File.ReadAllText(fiCustomers.FullName);
                        Customers = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
    
                        lvwCustomers.Items.Clear();
    
                        foreach (Customer wm in Customers)
                        {
                            ListViewItem lviCustomer = new ListViewItem(wm.CustomerId.ToString());
    
                            lviCustomer.SubItems.Add(wm.AccountNumber);
                            lviCustomer.SubItems.Add(wm.AccountName);
                            lviCustomer.SubItems.Add(wm.MeterNumber);
    
                            TextReader trAccountsTypess = new StreamReader(fiAccountsTypes.FullName);
                            strAccountsTypes = File.ReadAllText(fiAccountsTypes.FullName);
                            accountsTypes = JsonSerializer.Deserialize<List<AccountType>>(strAccountsTypes)!;
    
                            foreach (AccountType at in accountsTypes)
                            {
                                if (wm.AccountType == at.TypeCode)
                                {
                                    lviCustomer.SubItems.Add(string.Concat(at.TypeCode, " - ", at.TypeDecription));
                                }
                            }
                            
                            lviCustomer.SubItems.Add(wm.Address);
                            lviCustomer.SubItems.Add(wm.City);
                            lviCustomer.SubItems.Add(wm.County);
                            lviCustomer.SubItems.Add(wm.State);
                            lviCustomer.SubItems.Add(wm.ZIPCode);
                            lvwCustomers.Items.Add(lviCustomer);
                        }
                    }
                }
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                ShowCustomers();
            }
    
            private void btnCreateCustomerAccount_Click(object sender, EventArgs e)
            {
                Create create = new();
    
                if (create.ShowDialog() == DialogResult.OK)
                {
                    if(create.mtbAccountNumber.Text.Replace("-", "").Trim().Equals(""))
                    {
                        MsgBox.Show("You must provide an account number for a new customer. " +
                                        "Otherwise, the account cannot be created.");
                        return;
                    }
    
                    if (create.mtbMeterNumber.Text.Replace("-", "").Trim().Equals(string.Empty))
                    {
                        MsgBox.Show("You must type a valid meter number to associate " +
                                        "a water meter to a customer's account. After providing " +
                                        "a meter number, click the Find Water Meter button.");
                        return;
                    }
    
                    string strCustomers = string.Empty;
                    List<Customer> clients = new List<Customer>();
                    string fileCustomers = @"C:\Stellar Water Point2\Customers.json";
    
                    FileInfo fiCustomers = new FileInfo(fileCustomers);
    
                    if (fiCustomers.Exists == true)
                    {
                        strCustomers = File.ReadAllText(fiCustomers.FullName);
                        clients = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
                    }
    
                    Customer client = new Customer()
                    {
                        CustomerId = int.Parse(create.txtCustomerId.Text),
                        AccountNumber = create.mtbAccountNumber.Text,
                        AccountName = create.txtAccountName.Text,
                        MeterNumber = create.mtbMeterNumber.Text,
                        AccountType = create.cbxAccountsTypes.Text.Substring(0, 3),
                        Address = create.txtAddress.Text,
                        City = create.txtCity.Text,
                        County = create.txtCounty.Text,
                        State = create.txtState.Text,
                        ZIPCode = create.mtbZIPCode.Text
                    };
    
                    clients.Add(client);
    
                    JsonSerializerOptions options = new JsonSerializerOptions();
                    options.WriteIndented = true;
    
                    string jsCustomers = JsonSerializer.Serialize(clients, typeof(List<Customer>), options);
                    File.WriteAllText(fiCustomers.FullName, jsCustomers);
                }
    
                ShowCustomers();
            }
    
            private void btnCustomerAccountDetails_Click(object sender, EventArgs e)
            {
                Details details = new();
    
                details.Show();
            }
    
            private void btnUpdateCustomerAccount_Click(object sender, EventArgs e)
            {
                Editor editor = new();
                
                editor.ShowDialog();
    
                ShowCustomers();
            }
    
            private void btnDeleteCustomerAccount_Click(object sender, EventArgs e)
            {
                Delete delete = new();
    
                delete.ShowDialog();
    
                ShowCustomers();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  17. To execute the application, on the main menu, click Debug -> Start Without Debugging:

    Stellar Water Point

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

    Stellar Water Point - Customers

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

    Stellar Water Point - Water Meter Deletion

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

    Stellar Water Point - Customer Account Deletion

  22. Click the Delete Customer Account button

    Stellar Water Point - Customers

  23. Read the text on the message box.
    On the message box, click Yes

    Stellar Water Point - Customers

  24. In the same way, delete the other two records
  25. Close the forms and return to your programming environment
  26. Open the Customers.json file. Replace its contents with the following and save:
    [
      {
        "CustomerId": 1,
        "AccountNumber": "9279-570-8394",
        "AccountName": "Thomas Stones",
        "MeterNumber": "799-528-461",
        "AccountType": "RES",
        "Address": "10252 Broward Ave #D4",
        "City": "Frederick",
        "County": "Frederick",
        "State": "MD",
        "ZIPCode": "21703-4422"
      },
      {
        "CustomerId": 2,
        "AccountNumber": "4086-938-4783",
        "AccountName": "Bernotte Doughnuts",
        "MeterNumber": "580-742-825",
        "AccountType": "BUS",
        "Address": "10103 Hexagon Drv",
        "City": "Winterstown",
        "County": "York",
        "State": "PA",
        "ZIPCode": "17402-8818"
      },
      {
        "CustomerId": 3,
        "AccountNumber": "2068-258-9486",
        "AccountName": "Yollanda Training",
        "MeterNumber": "186-962-805",
        "AccountType": "UUO",
        "Address": "4819 East Munk Street",
        "City": "Whitehall",
        "County": "Fulton",
        "State": "PA",
        "ZIPCode": "17340-1188"
      },
      {
        "CustomerId": 4,
        "AccountNumber": "6986-829-3741",
        "AccountName": "Eyes Wide",
        "MeterNumber": "208-428-308",
        "AccountType": "BUS",
        "Address": "12087 Avencia Court #4D1",
        "City": "Silver Spring",
        "County": "Montgomery",
        "State": "MD",
        "ZIPCode": "20910-2288"
      },
      {
        "CustomerId": 5,
        "AccountNumber": "9947-374-2648",
        "AccountName": "Marianne Harrington",
        "MeterNumber": "862-715-006",
        "AccountType": "RES",
        "Address": "708 Correta Drv",
        "City": "Arlington",
        "County": "",
        "State": "VA",
        "ZIPCode": "22222-6060"
      },
      {
        "CustomerId": 6,
        "AccountNumber": "4293-802-8506",
        "AccountName": "Kelly Davids",
        "MeterNumber": "496-813-794",
        "AccountType": "RES",
        "Address": "938 East Panchot Str",
        "City": "Greenwood",
        "County": "Sussex",
        "State": "DE",
        "ZIPCode": "19950-4242"
      },
      {
        "CustomerId": 7,
        "AccountNumber": "6240-857-4965",
        "AccountName": "First Methodist Congregation",
        "MeterNumber": "739-777-749",
        "AccountType": "RES",
        "Address": "7702 Charles Road",
        "City": "",
        "County": "",
        "State": "",
        "ZIPCode": ""
      },
      {
        "CustomerId": 8,
        "AccountNumber": "7928-131-4850",
        "AccountName": "Department of Public Affairs",
        "MeterNumber": "",
        "AccountType": "SGO",
        "Address": "",
        "City": "Hyattsville",
        "County": "Prince Georges",
        "State": "MD",
        "ZIPCode": "20783-2277"
      },
      {
        "CustomerId": 9,
        "AccountNumber": "1386-949-2058",
        "AccountName": "Watson Country Buffet",
        "MeterNumber": "296-837-495",
        "AccountType": "WAT",
        "Address": "4862 Wellington Street",
        "City": "Hammonton",
        "County": "Atlantic ",
        "State": "NJ",
        "ZIPCode": "08037-2828"
      },
      {
        "CustomerId": 10,
        "AccountNumber": "7943-686-9786",
        "AccountName": "Angel Bulzaides",
        "MeterNumber": "394-835-297",
        "AccountType": "RES",
        "Address": "10227 Old Harbor Drv",
        "City": "Elkview",
        "County": "Kanawha",
        "State": "WV",
        "ZIPCode": "25071-5858"
      },
      {
        "CustomerId": 11,
        "AccountNumber": "4820-375-2842",
        "AccountName": "Sun Communal",
        "MeterNumber": "392-494-572",
        "AccountType": "SGO",
        "Address": "748 Red Hills Rd",
        "City": "Roanoke",
        "County": "",
        "State": "VA",
        "ZIPCode": "24012-4824"
      },
      {
        "CustomerId": 12,
        "AccountNumber": "9618-579-2577",
        "AccountName": "Gerald Place",
        "MeterNumber": "847-252-246",
        "AccountType": "UUO",
        "Address": "3666 Hanchor Drv",
        "City": "Granville",
        "County": "Licking",
        "State": "OH",
        "ZIPCode": "43023-2777"
      },
      {
        "CustomerId": 13,
        "AccountNumber": "",
        "AccountName": "",
        "MeterNumber": "",
        "AccountType": "",
        "Address": "",
        "City": "",
        "County": "",
        "State": "",
        "ZIPCode": ""
      },
      {
        "CustomerId": 14,
        "AccountNumber": "2037-495-8528",
        "AccountName": "Astral Sequence",
        "MeterNumber": "",
        "AccountType": "BUS",
        "Address": "12715 Eastern Gateway",
        "City": "Catonsville",
        "County": "Baltimore County",
        "State": "",
        "ZIPCode": ""
      },
      {
        "CustomerId": 15,
        "AccountNumber": "6003-386-3955",
        "AccountName": "Mandiakandara Marmoudi",
        "MeterNumber": "374-886-284",
        "AccountType": "OTH",
        "Address": "539 Avalon Court",
        "City": "Greenwood",
        "County": "Sussex",
        "State": "DE",
        "ZIPCode": "19950-5550"
      },
      {
        "CustomerId": 16,
        "AccountNumber": "5294-859-7513",
        "AccountName": "Jeannette Schiller",
        "MeterNumber": "713-942-058",
        "AccountType": "RES",
        "Address": "10110 Winslow Ave",
        "City": "Mercerville",
        "County": "Mercer",
        "State": "NJ",
        "ZIPCode": "08619-7472"
      },
      {
        "CustomerId": 17,
        "AccountNumber": "9249-379-6848",
        "AccountName": "Country West Eatery",
        "MeterNumber": "588-279-663",
        "AccountType": "BUS",
        "Address": "8280 Sligo North Way",
        "City": "Albright",
        "County": "Preston",
        "State": "WV",
        "ZIPCode": "26519-6620"
      },
      {
        "CustomerId": 18,
        "AccountNumber": "5252-757-9595",
        "AccountName": "Sathyavanthara Khooni",
        "MeterNumber": "379-386-979",
        "AccountType": "RES",
        "Address": "4992 Preston Street",
        "City": "",
        "County": "",
        "State": "OH",
        "ZIPCode": ""
      },
      {
        "CustomerId": 19,
        "AccountNumber": "7080-583-5947",
        "AccountName": "Sunny Yard",
        "MeterNumber": "827-508-248",
        "AccountType": "WAT",
        "Address": "663 Sherry Wood East Street",
        "City": "Shimpstown",
        "County": "Franklin",
        "State": "PA",
        "ZIPCode": "17236-2626"
      },
      {
        "CustomerId": 20,
        "AccountNumber": "8027-304-6829",
        "AccountName": "Anthony Clarcksons",
        "MeterNumber": "837-806-836",
        "AccountType": "RES",
        "Address": "904 Augusta Drive",
        "City": "Blackbird",
        "County": "New Castle",
        "State": "DE",
        "ZIPCode": "19734-8822"
      },
      {
        "CustomerId": 21,
        "AccountNumber": "6699-396-2905",
        "AccountName": "Spencer Reuter",
        "MeterNumber": "649-373-505",
        "AccountType": "RES",
        "Address": "2850 Burnsweak Avenue",
        "City": "Silver Spring",
        "County": "Montgomery",
        "State": "MD",
        "ZIPCode": "20910-4044"
      },
      {
        "CustomerId": 22,
        "AccountNumber": "1827-395-0203",
        "AccountName": "Watson Country Buffet",
        "MeterNumber": "470-628-850",
        "AccountType": "WAT",
        "Address": "10331 Chryswell Road",
        "City": "Washington",
        "County": "",
        "State": "DC",
        "ZIPCode": "20008-2426"
      },
      {
        "CustomerId": 23,
        "AccountNumber": "5862-736-9741",
        "AccountName": "Eastern Cage",
        "MeterNumber": "",
        "AccountType": "BUS",
        "Address": "2039 Night Stand Court",
        "City": "Hammonton",
        "County": "",
        "State": "NJ",
        "ZIPCode": ""
      },
      {
        "CustomerId": 24,
        "AccountNumber": "3947-957-4958",
        "AccountName": "Patsil Industries",
        "MeterNumber": "747-581-379",
        "AccountType": "BUS",
        "Address": "10348 Larrens Drive",
        "City": "Baltimore",
        "County": "Baltimore",
        "State": "MD",
        "ZIPCode": "21215-2222"
      },
      {
        "CustomerId": 25,
        "AccountNumber": "2836-485-9699",
        "AccountName": "Red Oak High School",
        "MeterNumber": "379-386-979",
        "AccountType": "SGO",
        "Address": "442 Donham Road",
        "City": "Silver Spring",
        "County": "Montgomery",
        "State": "MD",
        "ZIPCode": "20910-8822"
      },
      {
        "CustomerId": 26,
        "AccountNumber": "5938-074-5293",
        "AccountName": "Park and Roll",
        "MeterNumber": "592-824-957",
        "AccountType": "SGO",
        "Address": "582G Dunhill Avenue",
        "City": "Lanham",
        "County": "Prince Georges",
        "State": "MD",
        "ZIPCode": "20706-8284"
      },
      {
        "CustomerId": 27,
        "AccountNumber": "3028-502-9418",
        "AccountName": "Spencer Kershaw",
        "MeterNumber": "186-959-757",
        "AccountType": "RES",
        "Address": "338C Grayson Street",
        "City": "Gatchellville",
        "County": "York",
        "State": "PA",
        "ZIPCode": "17352-6464"
      },
      {
        "CustomerId": 28,
        "AccountNumber": "9684-759-2227",
        "AccountName": "Country West Eatery",
        "MeterNumber": "928-317-924",
        "AccountType": "BUS",
        "Address": "",
        "City": "",
        "County": "",
        "State": "",
        "ZIPCode": ""
      },
      {
        "CustomerId": 29,
        "AccountNumber": "2974-972-8139",
        "AccountName": "Paul Arnette",
        "MeterNumber": "295-770-695",
        "AccountType": "OTH",
        "Address": "8127 Bledsoe Str",
        "City": "Hyattsville",
        "County": "Prince Georges",
        "State": "MD",
        "ZIPCode": "20783-5858"
      },
      {
        "CustomerId": 30,
        "AccountNumber": "2758-493-7249",
        "AccountName": "Hervey Smile",
        "MeterNumber": "293-924-869",
        "AccountType": "WAT",
        "Address": "12973 Sonaa Street #E42",
        "City": "Silver Spring",
        "County": "Montgomery",
        "State": "MD",
        "ZIPCode": "20910-4488"
      },
      {
        "CustomerId": 31,
        "AccountNumber": "9337-947-3664",
        "AccountName": "Awesome Aid",
        "MeterNumber": "649-358-184",
        "AccountType": "SGO",
        "Address": "",
        "City": "Bellefontaine",
        "County": "",
        "State": "OH",
        "ZIPCode": ""
      },
      {
        "CustomerId": 32,
        "AccountNumber": "7518-302-6895",
        "AccountName": "Grace Brenner",
        "MeterNumber": "207-964-835",
        "AccountType": "BUS",
        "Address": "4299 Peachtree Court",
        "City": "Rockville",
        "County": "Montgomery",
        "State": "MD",
        "ZIPCode": "20853-1888"
      },
      {
        "CustomerId": 33,
        "AccountNumber": "2937-947-3008",
        "AccountName": "Jeffrey Maney",
        "MeterNumber": "",
        "AccountType": "RES",
        "Address": "",
        "City": "",
        "County": "",
        "State": "",
        "ZIPCode": ""
      },
      {
        "CustomerId": 34,
        "AccountNumber": "7028-405-9381",
        "AccountName": "Valley Services",
        "MeterNumber": "306-842-497",
        "AccountType": "WAT",
        "Address": "613 Meadowhill Road",
        "City": "Alonzaville",
        "County": "Shenandoah",
        "State": "VA",
        "ZIPCode": "22664-8080"
      },
      {
        "CustomerId": 35,
        "AccountNumber": "5293-957-3395",
        "AccountName": "Wellway Community Center",
        "MeterNumber": "386-468-057",
        "AccountType": "RES",
        "Address": "10484 Greenway Avenue",
        "City": "Mt Storm",
        "County": "Grant",
        "State": "WV",
        "ZIPCode": "26739-7700"
      },
      {
        "CustomerId": 36,
        "AccountNumber": "2038-413-9680",
        "AccountName": "Eastern Friandise",
        "MeterNumber": "938-725-869",
        "AccountType": "BUS",
        "Address": "2075 Rose Hills Avenue",
        "City": "Washington",
        "County": "",
        "State": "DC",
        "ZIPCode": "20004-2626"
      },
      {
        "CustomerId": 37,
        "AccountNumber": "7484-744-9708",
        "AccountName": "Amidou Gomah",
        "MeterNumber": "",
        "AccountType": "RES",
        "Address": "14118 Yellow Burrough Blvd",
        "City": "Philadelphia",
        "County": "",
        "State": "PA",
        "ZIPCode": ""
      },
      {
        "CustomerId": 38,
        "AccountNumber": "3792-853-6885",
        "AccountName": "Department of Public Affairs",
        "MeterNumber": "595-753-147",
        "AccountType": "",
        "Address": "",
        "City": "Upper Marlboro",
        "County": "Prince George County",
        "State": "",
        "ZIPCode": ""
      },
      {
        "CustomerId": 39,
        "AccountNumber": "8282-777-8282",
        "AccountName": "Garland Hotel",
        "MeterNumber": "938-275-294",
        "AccountType": "BUS",
        "Address": "4222 Extell Ave",
        "City": "Cambridge",
        "County": "",
        "State": "MD",
        "ZIPCode": "21613-2288"
      },
      {
        "CustomerId": 40,
        "AccountNumber": "5975-863-7057",
        "AccountName": "Single Connection",
        "MeterNumber": "288-427-585",
        "AccountType": "BUS",
        "Address": "",
        "City": "Mansfield",
        "County": "",
        "State": "OH",
        "ZIPCode": "44903-3030"
      },
      {
        "CustomerId": 41,
        "AccountNumber": "2499-636-4444",
        "AccountName": "Bryanna Spencer",
        "MeterNumber": "",
        "AccountType": "RES",
        "Address": "6282 Sheppherd Str",
        "City": "",
        "County": "Anne Arundel",
        "State": "",
        "ZIPCode": ""
      },
      {
        "CustomerId": 42,
        "AccountNumber": "2842-585-7260",
        "AccountName": "District Community Reserves",
        "MeterNumber": "349-725-848",
        "AccountType": "SGO",
        "Address": "3280 Hopewell Street, NE",
        "City": "Washington",
        "County": "",
        "State": "",
        "ZIPCode": ""
      },
      {
        "CustomerId": 43,
        "AccountNumber": "9282-794-7937",
        "AccountName": "Yashua Yáñés",
        "MeterNumber": "392-494-572",
        "AccountType": "RES",
        "Address": "10214 Monroe Ave",
        "City": "Easton",
        "County": "",
        "State": "MD",
        "ZIPCode": ""
      },
      {
        "CustomerId": 44,
        "AccountNumber": "6837-468-4750",
        "AccountName": "Miguel Altieri",
        "MeterNumber": "",
        "AccountType": "RES",
        "Address": "10941 Patriot Blvd",
        "City": "Crenshaw",
        "County": "Jefferson",
        "State": "PA",
        "ZIPCode": "15824-6628"
      },
      {
        "CustomerId": 45,
        "AccountNumber": "2847-597-2829",
        "AccountName": "Jameson",
        "MeterNumber": "379-386-979",
        "AccountType": "WAT",
        "Address": "7373 Gold Town Rd",
        "City": "",
        "County": "",
        "State": "WV",
        "ZIPCode": ""
      },
      {
        "CustomerId": 46,
        "AccountNumber": "6381-748-2222",
        "AccountName": "Up Eyes",
        "MeterNumber": "",
        "AccountType": "BUS",
        "Address": "4149 Deerfield Str",
        "City": "",
        "County": "",
        "State": "",
        "ZIPCode": ""
      },
      {
        "CustomerId": 47,
        "AccountNumber": "4968-274-9638",
        "AccountName": "Annette Wald",
        "MeterNumber": "",
        "AccountType": "RES",
        "Address": "11441  Eastern Friendshi Rd",
        "City": "",
        "County": "",
        "State": "",
        "ZIPCode": ""
      },
      {
        "CustomerId": 48,
        "AccountNumber": "8384-708-2941",
        "AccountName": "Department of Environment Affairs",
        "MeterNumber": "",
        "AccountType": "SGO",
        "Address": "",
        "City": "",
        "County": "",
        "State": "OH",
        "ZIPCode": ""
      },
      {
        "CustomerId": 49,
        "AccountNumber": "3728-138-2947",
        "AccountName": "Marie Rath",
        "MeterNumber": "",
        "AccountType": "",
        "Address": "8802 Atlantic Ave",
        "City": "",
        "County": "",
        "State": "PA",
        "ZIPCode": ""
      },
      {
        "CustomerId": 50,
        "AccountNumber": "1793-857-9413",
        "AccountName": "Body Care",
        "MeterNumber": "",
        "AccountType": "WAT",
        "Address": "",
        "City": "Ocean City",
        "County": "",
        "State": "NJ",
        "ZIPCode": ""
      },
      {
        "CustomerId": 51,
        "AccountNumber": "6028-695-2068",
        "AccountName": "Ronald Glassman",
        "MeterNumber": "468-359-486",
        "AccountType": "BUS",
        "Address": "",
        "City": "",
        "County": "",
        "State": "",
        "ZIPCode": ""
      },
      {
        "CustomerId": 52,
        "AccountNumber": "4069-37-49728",
        "AccountName": "Lucette Wash N Dry",
        "MeterNumber": "",
        "AccountType": "WAT",
        "Address": "8812 Lawrence Ave",
        "City": "",
        "County": "",
        "State": "NW",
        "ZIPCode": ""
      },
      {
        "CustomerId": 53,
        "AccountNumber": "9616-283-7249",
        "AccountName": "Department of Public Affairs",
        "MeterNumber": "",
        "AccountType": "SGO",
        "Address": "13006 Blueberry Ave",
        "City": "Greenbelt",
        "County": "",
        "State": "MD",
        "ZIPCode": "20770-2040"
      },
      {
        "CustomerId": 54,
        "AccountNumber": "2829-516-8353",
        "AccountName": "Richard Eghert",
        "MeterNumber": "",
        "AccountType": "RES",
        "Address": "662 Placido Road",
        "City": "",
        "County": "",
        "State": "",
        "ZIPCode": ""
      },
      {
        "CustomerId": 55,
        "AccountNumber": "6296-875-9607",
        "AccountName": "Country West Eatery",
        "MeterNumber": "",
        "AccountType": "BUS",
        "Address": "837 Larrenson Drv",
        "City": "Cumberland",
        "County": "",
        "State": "MD",
        "ZIPCode": ""
      },
      {
        "CustomerId": 56,
        "AccountNumber": "9684-794-6379",
        "AccountName": "Eye Care",
        "MeterNumber": "",
        "AccountType": "BUS",
        "Address": "8626 Cameron Str",
        "City": "",
        "County": "",
        "State": "",
        "ZIPCode": ""
      },
      {
        "CustomerId": 57,
        "AccountNumber": "2405-839-5820",
        "AccountName": "Watson Country Buffet",
        "MeterNumber": "",
        "AccountType": "WAT",
        "Address": "",
        "City": "Harrisburg",
        "County": "",
        "State": "PA",
        "ZIPCode": ""
      }
    ]

Water Bills

Introduction

A water bill is an intermediary document between the water distribution company and a consumer. We will create the classes, forms, and operations to present that information.

Practical LearningPractical Learning: Introducing Water Bills

  1. To create a folder, in the Solution Explorer, right-click the StellarWaterPoint2 project -> Add -> New Folder
  2. Type WaterBills as the name of the folder
  3. To create a class, in the Solution Explorer, right-click Models -> Add -> Class...
  4. Type WaterBill as the Name of the file
  5. Click Add
  6. Define the class as follows:
    namespace StellarWaterPoint2.Models
    {
        public class WaterBill
        {
            public int      BillNumber            { get; set; }
            public string?  AccountNumber         { get; set; }
            public DateTime MeterReadingStartDate { get; set; }
            public DateTime MeterReadingEndDate   { get; set; }
            public int      BillingDays           { get; set; }
            public int      CounterReadingStart   { get; set; }
            public int      CounterReadingEnd     { get; set; }
            public int      TotalHCF              { get; set; }
            public int      TotalGallons          { get; set; }
            public double   FirstTierConsumption  { get; set; }
            public double   SecondTierConsumption { get; set; }
            public double   LastTierConsumption   { get; set; }
            public double   WaterCharges          { get; set; }
            public double   SewerCharges          { get; set; }
            public double   EnvironmentCharges    { get; set; }
            public double   ServiceCharges        { get; set; }
            public double   TotalCharges          { get; set; }
            public double   LocalTaxes            { get; set; }
            public double   StateTaxes            { get; set; }
            public DateTime PaymentDueDate        { get; set; }
            public double   AmountDue             { get; set; }
            public DateTime LatePaymentDueDate    { get; set; }
            public double   LateAmountDue         { get; set; }
        }
    }
  7. To create another class, in the Solution Explorer, right-click Models -> Add -> Class...
  8. Type WaterBillManager as the Name of the file
  9. Click Add
  10. Define the class as follows:
    namespace StellarWaterPoint2.Models
    {
        internal static class WaterBillManager
        {
            internal static (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 * 39.35 / 10000.00;
                        results.tier2 = total * 18.25 / 10000.00;
                        results.tier3 = total * 11.65 / 10000.00;
                        break;
                    case "SGO":
                        results.tier1 = total * 41.38 / 10000.00;
                        results.tier2 = total * 15.26 / 10000.00;
                        results.tier3 = total * 8.13 / 10000.00;
                        break;
                    case "BUS":
                        results.tier1 = total * 51.25 / 10000.00;
                        results.tier2 = total * 34.65 / 10000.00;
                        results.tier3 = total * 15.10 / 10000.00;
                        break;
                    case "UUO":
                        results.tier1 = total * 25.00 / 10000.00;
                        results.tier2 = total * 35.00 / 10000.00;
                        results.tier3 = total * 40.00 / 10000.00;
                        break;
                    case "WAT":
                        results.tier1 = (total / 6) * 3 * 50.00 / 10000.00;
                        results.tier2 = (total / 6) * 2 * 35.00 / 10000.00;
                        results.tier3 = total * 15.00 / 10000.00;
                        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;
            }
    
            internal static double CalculateSewerCharges(string acnt, double total)
            {
                double result;
    
                if (acnt == "RES")
                {
                    result = total * 1.028641 / 100.00;
                }
                else if (acnt == "SGO")
                {
                    result = total * 4.162522 / 100.00;
                }
                else if (acnt == "BUS")
                {
                    result = total * 8.446369 / 100.00;
                }
                else if (acnt == "UUO")
                {
                    result = total * 10.622471 / 100.00;
                }
                else if (acnt == "WAT")
                {
                    result = total * 12.053152 / 100.00;
                }
                else // if (acnt == "OTH)"
                {
                    result = total * 9.206252 / 100.00;
                }
    
                return result;
            }
    
            internal static double CalculateEnvironmentCharges(string acnt, double total)
            {
                double result;
    
                switch (acnt)
                {
                    case "RES":
                        result = total * 0.004524;
                        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;
            }
    
            internal static double CalculateServiceCharges(string acnt, double total)
            {
                switch (acnt)
                {
                    case "RES":
                        return total * 0.006248;
                    case "SGO":
                        return total * 0.102246;
                    case "BUS":
                        return total * 0.155227;
                    case "UUO":
                        return total * 0.186692;
                    case "WAT":
                        return total * 0.412628;
                    default:
                        return total * 0.210248;
                }
            }
    
            internal static double CalculateLocalTaxes(string acnt, double total) => acnt switch
            {
                "RES" => total * 0.035749,
                "SGO" => total * 0.044026,
                "BUS" => total * 0.122517,
                "UUO" => total * 0.105737,
                "WAT" => total * 0.153248,
                _ => total * 0.125148
            };
    
            internal static double CalculateStateTaxes(string acnt, double total) => acnt switch
            {
                "RES" => total * 0.007124,
                "SGO" => total * 0.008779,
                "BUS" => total * 0.042448,
                "UUO" => total * 0.067958,
                "WAT" => total * 0.081622,
                _ => total * 0.013746
            };
    
            internal static 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;
            }
    
            internal static 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);
                }
            }
    
            internal static 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)
            };
        }
    }

Showing Water Bills

A water distribution company has many records for water bills, and a typical water bill includes many pieces of information. We will create a form that displays a list of some pieces of information about a water bill.

Practical LearningPractical Learning: Showing Water Bills

  1. To create a form, in the Solution Explorer, right-click WaterBills -> Add -> Form (Windows Forms)...
  2. For 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 TextAlign Width
    colWaterBillId Id   40
    colBillNumber Bill # Center 80
    colAccountSummary Account Summary Center 550
    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 95
    colPaymentDueDate Pmt Due Date Center 125
    colAmountDue Amt Due Right 90
  7. Click OK
  8. Position and resize the list view on the form as follows:

    Stellar Water Point - Water Bills

    Control (Name) Other Properties
    ListView List View lvwWaterBills FullRowSelect: True
    GridLines: True
    View: Details
  9. Double-click an unoccupied area of the form to generate its Load event
  10. Change the document as follows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.WaterBills
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowWaterBills()
            {
                string strCustomers = string.Empty;
                
                List<Customer> clients = new List<Customer>();
                
                string fileCustomers = @"C:\Stellar Water Point2\Customers.json";
    
                FileInfo fiCustomers = new FileInfo(fileCustomers);
    
                if (fiCustomers.Exists == true)
                {
                    using (TextReader trCustomers = new StreamReader(fiCustomers.FullName))
                    {
                        strCustomers = File.ReadAllText(fiCustomers.FullName);
                        
                        clients = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
                    }
                }
    
                string strWaterBills = string.Empty;
                List<WaterBill> bills = new List<WaterBill>();
                
                string fileWaterBills = @"C:\Stellar Water Point2\WaterBills.json";
    
                FileInfo fiWaterBills = new FileInfo(fileWaterBills);
    
                if (fiWaterBills.Exists == true)
                {
                    using (TextReader trWaterBills = new StreamReader(fiWaterBills.FullName))
                    {
                        strWaterBills = File.ReadAllText(fiWaterBills.FullName);
                        
                        bills = JsonSerializer.Deserialize<List<WaterBill>>(strWaterBills)!;
    
                        lvwWaterBills.Items.Clear();
    
                        foreach (WaterBill invoice in bills)
                        {
                            ListViewItem lviWaterBill = new ListViewItem(invoice.WaterBillId.ToString());
    
                            lviWaterBill.SubItems.Add(invoice.BillNumber.ToString());
    
                            IEnumerable<Customer> customer = clients.Where(cust => cust.AccountNumber == invoice.AccountNumber);
    
                            foreach (Customer cust in customer)
                            {
                                lviWaterBill.SubItems.Add(invoice.AccountNumber + " - " +
                                                          cust.AccountName +
                                                          ", Type: " + cust.AccountType![..3] +
                                                          ", (Mtr #: " + cust.MeterNumber + ")");
                            }
    
                            lviWaterBill.SubItems.Add(invoice.MeterReadingStartDate.ToShortDateString());
                            lviWaterBill.SubItems.Add(invoice.MeterReadingEndDate.ToShortDateString());
                            lviWaterBill.SubItems.Add(invoice.BillingDays.ToString());
                            lviWaterBill.SubItems.Add(invoice.CounterReadingStart.ToString());
                            lviWaterBill.SubItems.Add(invoice.CounterReadingEnd.ToString());
                            lviWaterBill.SubItems.Add(invoice.TotalHCF.ToString());
                            lviWaterBill.SubItems.Add(invoice.TotalGallons.ToString());
                            lviWaterBill.SubItems.Add(invoice.PaymentDueDate.ToShortDateString());
                            lviWaterBill.SubItems.Add(invoice.AmountDue.ToString());
    
                            lvwWaterBills.Items.Add(lviWaterBill);
                        }
                    }
                }
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                ShowWaterBills();
            }
        }
    }
  11. In the Solution Explorer, double-click WaterDistribution.cs to display the main form of the application
  12. From the Toolbox, add two buttons 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 btnWaterBills C&Water Bills... Times New Roman, 24pt, style=Bold
    Button Button btnClose &Close Times New Roman, 24pt, style=Bold
  14. Double-click the &Water Bills button
  15. Return to the form and double-click the Close button
  16. Impliment the events as follows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2
    {
        public partial class WaterDistribution : Form
        {
            private void CreateWaterMeters()
            {
                List<WaterMeter> waterMeters = new List<WaterMeter>();
    
                waterMeters!.Add(new WaterMeter() { WaterMeterId =  1, MeterNumber = "392-494-572", Make = "Constance Technologies", Model = "TG-4822",  MeterSize = "5/8 Inches"   });
                waterMeters.Add(new  WaterMeter() { WaterMeterId =  2, MeterNumber = "938-725-869", Make = "Stanford Trend",         Model = "266G",     MeterSize = "1 1/2 Inches" });
                waterMeters.Add(new  WaterMeter() { WaterMeterId =  3, MeterNumber = "588-279-663", Make = "Estellano",              Model = "NCF-226",  MeterSize = "4 Inches"     });
                waterMeters.Add(new  WaterMeter() { WaterMeterId =  4, MeterNumber = "186-962-805", Make = "Lansome",                Model = "2800",     MeterSize = "1 1/2 Inches" });
                waterMeters.Add(new  WaterMeter() { WaterMeterId =  5, MeterNumber = "379-386-979", Make = "Planetra",               Model = "P-2020",   MeterSize = "4 Inches"     });
                waterMeters.Add(new  WaterMeter() { WaterMeterId =  6, MeterNumber = "580-742-825", Make = "Kensa Sons",             Model = "KS2000A",  MeterSize = "1 3/4 Inches" });
                waterMeters.Add(new  WaterMeter() { WaterMeterId =  7, MeterNumber = "849-351-444", Make = "Raynes Energica",        Model = "a1088",    MeterSize = "2 Inches"     });
                waterMeters.Add(new  WaterMeter() { WaterMeterId =  8, MeterNumber = "208-428-308", Make = "Constance Technologies", Model = "808D",     MeterSize = "3/4 Inches"   });
                waterMeters.Add(new  WaterMeter() { WaterMeterId =  9, MeterNumber = "738-588-249", Make = "Warrington",             Model = "W4242",    MeterSize = "5/8 Inches"   });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 10, MeterNumber = "496-813-794", Make = "Estellano",              Model = "NCF-226",  MeterSize = "3/4 Inches"   });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 11, MeterNumber = "862-715-006", Make = "Warrington",             Model = "W-4040",   MeterSize = "1/2 Inch"     });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 12, MeterNumber = "649-358-184", Make = "Raynes Energica",        Model = "b1700",    MeterSize = "1 1/2 Inches" });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 13, MeterNumber = "928-317-924", Make = "Gongola",                Model = "GN1000",   MeterSize = "2 Inch"       });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 14, MeterNumber = "595-753-147", Make = "Grass Grill",            Model = "CRC-1000", MeterSize = "1 Inch"       });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 15, MeterNumber = "799-528-461", Make = "Kensa Sons",             Model = "K-584-L",  MeterSize = "3/4 Inches"   });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 16, MeterNumber = "386-468-057", Make = "Estellano",              Model = "NCF-226",  MeterSize = "3/4 Inches"   });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 17, MeterNumber = "938-275-294", Make = "Constance Technologies", Model = "TT-8822",  MeterSize = "4 Inches"     });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 18, MeterNumber = "288-427-585", Make = "Planetra",               Model = "P-2020",   MeterSize = "1/2 Inch"     });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 19, MeterNumber = "394-835-297", Make = "Raynes Energica",        Model = "i2022",    MeterSize = "3/4 Inches"   });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 20, MeterNumber = "847-252-246", Make = "Master Stream",          Model = "2000-MS",  MeterSize = "1 1/2 Inches" });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 21, MeterNumber = "349-725-848", Make = "Planetra",               Model = "P-8000",   MeterSize = "4 Inches"     });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 22, MeterNumber = "713-942-058", Make = "Master Stream",          Model = "3366-MS",  MeterSize = "3/4 Inches"   });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 23, MeterNumber = "747-581-379", Make = "Warrington",             Model = "W4242",    MeterSize = "5/8 Inches"   });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 24, MeterNumber = "582-755-263", Make = "Kensa Sons",             Model = "KS2000A",  MeterSize = "1 Inch"       });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 25, MeterNumber = "827-260-758", Make = "Raynes Energica",        Model = "a1088",    MeterSize = "1-1/4 Inch"   });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 26, MeterNumber = "837-806-836", Make = "Lansome",                Model = "7400",     MeterSize = "5/8 Inches"   });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 27, MeterNumber = "207-964-835", Make = "Constance Technologies", Model = "TG-6220",  MeterSize = "5/8 Inches"   });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 28, MeterNumber = "296-837-495", Make = "Raynes Energica",        Model = "QG505",    MeterSize = "4 Inches"     });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 29, MeterNumber = "468-359-486", Make = "Grass Grill",            Model = "KLP-8822", MeterSize = "1-1/4 Inch"   });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 30, MeterNumber = "931-486-003", Make = "Planetra",               Model = "P-2020",   MeterSize = "1/2 Inch"     });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 31, MeterNumber = "483-770-648", Make = "Warren",                 Model = "WWW",      MeterSize = "0.1 Inches"   });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 32, MeterNumber = "592-824-957", Make = "Kensa Sons",             Model = "D-497-H",  MeterSize = "3/4 Inches"   });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 33, MeterNumber = "293-835-704", Make = "Gongola",                Model = "GOL1000",  MeterSize = "1/2 Inch"     });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 34, MeterNumber = "739-777-749", Make = "Warrington",             Model = "W2200W",   MeterSize = "3/4 Inches"   });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 35, MeterNumber = "374-886-284", Make = "Raynes Energica",        Model = "i2022",    MeterSize = "3/4 Inches"   });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 36, MeterNumber = "186-959-757", Make = "Kensa Sons",             Model = "M-686-G",  MeterSize = "1 1/2 Inches" });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 37, MeterNumber = "594-827-359", Make = "Planetra",               Model = "P-8000",   MeterSize = "1 Inch"       });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 38, MeterNumber = "394-739-242", Make = "Master Stream",          Model = "9393-TT",  MeterSize = "5/8 Inches" });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 39, MeterNumber = "529-283-752", Make = "Constance Technologies", Model = "404T",     MeterSize = "3/4 Inches" });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 40, MeterNumber = "295-770-695", Make = "Warrington",             Model = "W-2286",   MeterSize = "1-1/4 Inch" });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 41, MeterNumber = "739-749-737", Make = "Kensa Sons",             Model = "KS2000A",  MeterSize = "1 Inch" });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 42, MeterNumber = "947-528-317", Make = "Gondola",                Model = "GDL-5000", MeterSize = "1 Inch" });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 43, MeterNumber = "630-207-055", Make = "Lansome",                Model = "2800",     MeterSize = "3/4 Inches" });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 44, MeterNumber = "827-508-248", Make = "Standard Trend",         Model = "428T",     MeterSize = "3/4 Inches" });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 45, MeterNumber = "293-924-869", Make = "Grass Grill",            Model = "CRC-2020", MeterSize = "1/2 Inch" });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 46, MeterNumber = "928-247-580", Make = "Gondola",                Model = "GOL2000",  MeterSize = "0.34 Inch" });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 47, MeterNumber = "682-537-380", Make = "Planetra",               Model = "P-2020",   MeterSize = "1-1/4 Inch" });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 48, MeterNumber = "470-628-850", Make = "Estellano",              Model = "WRT-482",  MeterSize = "3/4 Inches" });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 49, MeterNumber = "649-373-505", Make = "Constance Technologies", Model = "BD-7000",  MeterSize = "5/8 Inches" });
                waterMeters.Add(new  WaterMeter() { WaterMeterId = 50, MeterNumber = "306-842-497", Make = "Lansome",                Model = "9000",     MeterSize = "3/4 Inches" });
    
                string strWaterMeters = string.Empty;
                string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
                JsonSerializerOptions options = new JsonSerializerOptions();
                options.WriteIndented = true;
    
                FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
                string jsWaterMeters = JsonSerializer.Serialize(waterMeters, typeof(List<WaterMeter>), options);
                File.WriteAllText(fiWaterMeters.FullName, jsWaterMeters);
            }
    
            private void CreateAccountsTypes()
            {
                List<AccountType> types = new List<AccountType>()
                {
                    new AccountType() { AccountTypeId = 1, TypeCode = "OTH", TypeDecription = "Other" },
                    new AccountType() { AccountTypeId = 3, TypeCode = "RES", TypeDecription = "Residential Household" },
                    new AccountType() { AccountTypeId = 2, TypeCode = "BUS", TypeDecription = "General Business, Commercial, Industrial" },
                    new AccountType() { AccountTypeId = 5, TypeCode = "UUO", TypeDecription = "Unidentified or Unclassified Type of Organization" },
                    new AccountType() { AccountTypeId = 4, TypeCode = "SGO", TypeDecription = "Social/Government/Non-Profit Organization, Institutional" },
                    new AccountType() { AccountTypeId = 6, TypeCode = "WAT", TypeDecription = "Water Intensive Business (Agricultural, Laudromat, Hair Salon, Restaurant, etc" }
                };
    
                string strAccountsTypes       = string.Empty;
                string fileAccountsTypes      = @"C:\Stellar Water Point2\AccountsTypes.json";
    
                JsonSerializerOptions options = new JsonSerializerOptions();
                options.WriteIndented         = true;
    
                FileInfo fiAccountsTypes      = new FileInfo(fileAccountsTypes);
                string jsAccountsTypes        = JsonSerializer.Serialize(types, typeof(List<AccountType>), options);
                File.WriteAllText(fiAccountsTypes.FullName, jsAccountsTypes);
            }
    
            public WaterDistribution()
            {
                InitializeComponent();
    
                // CreateWaterMeters();
                // CreateAccountsTypes();
            }
    
            private void WaterDistribution_Load(object sender, EventArgs e)
            {
                Directory.CreateDirectory(@"C:\Stellar Water Point2");
            }
    
            private void btnWaterBills_Click(object sender, EventArgs e)
            {
                WaterBills.Central central = new WaterBills.Central();
    
                central.Show();
            }
    
            private void btnCustomers_Click(object sender, EventArgs e)
            {
                Customers.Central central = new Customers.Central();
    
                central.Show();
            }
    
            private void btnWaterMeters_Click(object sender, EventArgs e)
            {
                WaterMeters.Central central = new WaterMeters.Central();
    
                central.Show();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }

A New Water Bill

A water is probably the most important aspect of water distribution. We will provide a form that allows an employee to register the information necessary for water consumption. Then we will perform some operations. Finally, we will present the amount the consumer should pay and when.

Practical LearningPractical Learning: Processing a Water Bill

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

    Stellar Water Point - New Water Bill

    Control Text Name Other Properties
    Label Label &Water Bill #:    
    TextBox Text Box   txtBillNumber  
    GroupBox Group Box Customer Information    
    Label Label &Account #:    
    MaskedTextBox Masked Text Box   mtbAccountNumber Mask: 0000-000-0000
    Button Button Find Customer &Account btnFindCustomerAccount  
    Label Label Account Name:    
    TextBox Text Box   txtAccountName  
    Label Label Account Type:    
    TextBox Text Box   txtAccountType  
    Label Label Address:    
    TextBox Text Box   txtAddress  
    TextBox Text Box   txtCity  
    TextBox Text Box   txtCounty  
    TextBox Text Box   txtState  
    TextBox Text Box   txtZIPCode  
    Label Label _________________________________________________    
    Label Label Meter Details:    
    TextBox Text Box   txtMeterDetails  
    GroupBox Group Box Meter Reading    
    Label Label Meter &Reading Start Date:    
    Date Time Picker Text Box   dtpMeterReadingStartDate  
    Label Label Meter Reading &End Date:    
    Date Time Picker Text Box   dtpMeterReadingEndDate  
    Label Label Coun&ter Reading Start:    
    TextBox Text Box   txtCounterReadingStart  
    Label Label Counter Readi&ng End:    
    TextBox Text Box   txtCounterReadingEnd  
    Button Button &Evaluate Water Bill btnEvaluateWaterBill Times New Roman, 24pt, style=Bold
    GroupBox Group Box Meter Result    
    Label Label Billing Days:    
    TextBox Text Box   txtBillingDays  
    Label Label Total HCF:    
    TextBox Text Box   txtTotalHCF  
    Label Label Total Gallons:    
    TextBox Text Box   txtTotalGallons  
    Label Label First Tier Consumption:    
    TextBox Text Box   txtFirstTierConsumption  
    Label Label Second Tier:    
    TextBox Text Box   txtSecondTierConsumption  
    Label Label Last Tier:    
    TextBox Text Box   txtLastTierConsumption  
    GroupBox Group Box Consumption Charges    
    Label Label Water Charges:    
    TextBox Text Box   txtWaterCharges  
    Label Label Sewer Charges:    
    TextBox Text Box   txtSewerCharges  
    Label Label Environment Charges:    
    TextBox Text Box   txtEnvironmentCharges  
    Label Label Service Charges:    
    TextBox Text Box   txtServiceCharges  
    Label Label Total Charges:    
    TextBox Text Box   txtTotalCharges  
    GroupBox Group Box Taxes    
    Label Label Local Taxes:    
    TextBox Text Box   txtLocalTaxes  
    Label Label State Taxes:    
    TextBox Text Box   txtStateTaxes  
    GroupBox Group Box Water Bill Payment    
    Label Label Payment Due Date:    
    Date Time Picker Text Box   dtpPaymentDueDate  
    Label Label Amount Due:    
    TextBox Text Box   txtAmountDue  
    Label Label Late Payment Due Date:    
    Date Time Picker Text Box   dtpLatePaymentDueDate  
    Label Label &Late Amount Due:    
    TextBox Text Box   txtLateAmountDue  
    Label Label Water Bill Id:&    
    TextBox Text Box   txtWaterBillId  
    Button Button Save Water Bill btnSaveWaterBill  
    Button Button &Close btnClose  

    Form Properties

    Form Property Value
    FormBorderStyle FixedDialog
    Text Stellar Water Point - Water Bill Processing
    StartPosition CenterScreen
    MaximizeBox False
    MinimizeBox False
  5. Double-click an unoccupied area of the form to generate its Load event
  6. Implement the event as follows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.WaterMeters
    {
        public partial class Create : Form
        {
            public Create()
            {
                InitializeComponent();
            }
    
            private void Create_Load(object sender, EventArgs e)
            {
                string strWaterBills = string.Empty;
                List<WaterBill> waterBills = new List<WaterBill>();
                string fileWaterBills = @"C:\Stellar Water Point2\WaterBills.json";
    
                FileInfo fiWaterBills = new FileInfo(fileWaterBills);
    
                int waterBillId = 0;
    
                if (fiWaterBills.Exists == true)
                {
    
                    using (TextReader trWaterBills = new StreamReader(fiWaterBills.FullName))
                    {
                        strWaterBills = File.ReadAllText(fiWaterBills.FullName);
                        waterBills = JsonSerializer.Deserialize<List<WaterBill>>(strWaterBills)!;
    
                        foreach (WaterBill wm in waterBills)
                        {
                            waterBillId = wm.WaterBillId;
                        }
                    }
                }
    
                txtWaterBillId.Text = (waterBillId + 1).ToString();
            }
        }
    }
  7. On the form, double-click the Find Customer Account button
  8. Change the document as follows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.WaterBills
    {
        public partial class Create : Form
        {
            public Create()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                string strAccountNumber = mtbAccountNumber.Text.Replace("-", "").Trim();
    
                if (string.IsNullOrEmpty(strAccountNumber))
                {
                    MsgBox.Show("You must type a valid account number of a customer, " +
                                    "and then click the Find Customer Account button.");
                    return;
                }
    
                string strCustomers = string.Empty;
                List<Customer> clients = new List<Customer>();
                string fileCustomers = @"C:\Stellar Water Point2\Customers.json";
    
                FileInfo fiCustomers = new FileInfo(fileCustomers);
    
                string strAccountsTypes = string.Empty;
                List<AccountType> accountsTypes = new List<AccountType>();
                string fileAccountsTypes = @"C:\Stellar Water Point2\AccountsTypes.json";
    
                FileInfo fiAccountsTypes = new FileInfo(fileAccountsTypes);
    
                string? strMeterNumber = string.Empty;
    
                if (fiCustomers.Exists == true)
                {
                    using (TextReader trCustomers = new StreamReader(fiCustomers.FullName))
                    {
                        strCustomers = File.ReadAllText(fiCustomers.FullName);
                        clients = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
    
                        IEnumerable<Customer> customers = clients.Where(cust => cust.AccountNumber == mtbAccountNumber.Text);
    
                        foreach (Customer client in customers)
                        {
                            txtAccountName.Text = client.AccountName;
                            strMeterNumber = client.MeterNumber;
                            
                            TextReader trAccountsTypess = new StreamReader(fiAccountsTypes.FullName);
                            strAccountsTypes = File.ReadAllText(fiAccountsTypes.FullName);
                            accountsTypes = JsonSerializer.Deserialize<List<AccountType>>(strAccountsTypes)!;
                            
                            foreach (AccountType at in accountsTypes)
                            {
                                if (client.AccountType == at.TypeCode)
                                {
                                    txtAccountType.Text = string.Concat(at.TypeCode, " - ", at.TypeDecription);
                                }
                            }
    
                            txtAddress.Text = client.Address;
                            txtCity.Text = client.City;
                            txtCounty.Text = client.County;
                            txtState.Text = client.State;
                            txtZIPCode.Text = client.ZIPCode;
                        }
                    }
                }
    
                if (strMeterNumber!.Length > 0)
                {
                    string strWaterMeters = string.Empty;
                    List<WaterMeter> waterMeters = new List<WaterMeter>();
                    string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
                    FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
                    if (fiWaterMeters.Exists == true)
                    {
                        strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
                        waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
    
                        IEnumerable<WaterMeter> meters = waterMeters.Where(wm => wm.MeterNumber == strMeterNumber);
    
                        foreach (WaterMeter meter in meters)
                        {
                            txtMeterDetails.Text = meter.WaterMeterId.ToString() + " - " +
                                                   meter.Make + " " +
                                                   meter.Model +
                                                   " (Meter Size: " + meter.MeterSize + ")";
                        }
                    }
                }
            }
        }
    }
  9. Return to the form and double-click the Meter Reading End Date date time picker to generate its Value Changed event
  10. Implement the event as follows:
    using System.Data;
    using Microsoft.Data.SqlClient;
    
    namespace StellarWaterPoint21.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();
            }
        }
    }
  11. Return to the form and double-click the Evaluate Water Bill button
  12. Implement the event as follows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.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();
            }
    
            private void btnEvaluateWaterBill_Click(object sender, EventArgs e)
            {
                double counterStart = 0, counterEnd = 0;
    
                try
                {
                    counterStart = double.Parse(txtCounterReadingStart.Text);
                }
                catch (FormatException feCRStart)
                {
                    MsgBox.Show("You must enter a valid value in the Counter Reading Start text box. " +
                                    "The error produced is: " + feCRStart.Message,
                                    "Stellar Water Point", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
    
                try
                {
                    counterEnd = double.Parse(txtCounterReadingEnd.Text);
                }
                catch (FormatException feCREnd)
                {
                    MsgBox.Show("You must enter a valid value in the Counter Reading End text box. " +
                                    "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 = WaterBillManager.CalculateTiers(strAccountType, gallons);
    
                double waterCharges           = tiers.first + tiers.second + tiers.last;
                double sewerCharges           = WaterBillManager.CalculateSewerCharges(strAccountType, waterCharges);
                double envCharges             = WaterBillManager.CalculateEnvironmentCharges(strAccountType, waterCharges);
                double srvCharges             = WaterBillManager.CalculateServiceCharges(strAccountType, waterCharges);
                double totalCharges           = waterCharges + sewerCharges + envCharges + srvCharges;
                double localTaxes             = WaterBillManager.CalculateLocalTaxes(strAccountType, waterCharges);
                double stateTaxes             = WaterBillManager.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       = WaterBillManager.SetPaymentDueDate(strAccountType, dtpMeterReadingEndDate.Value);
                txtAmountDue.Text             = amtDue.ToString("F");
                dtpLatePaymentDueDate.Value   = WaterBillManager.SetLatePaymentDueDate(strAccountType, dtpMeterReadingEndDate.Value);
                txtLateAmountDue.Text         = WaterBillManager.CalculateLateAmountDue(strAccountType, amtDue).ToString("F");
            }
        }
    }
  13. Return to the form and double-click the Save Water Bill button
  14. Return to the form and double-click the Close button to generate its Click event
  15. Implement the events as follows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.WaterBills
    {
        public partial class Create : Form
        {
            public Create()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                if (string.IsNullOrEmpty(mtbAccountNumber.Text))
                {
                    MsgBox.Show("You must type a valid account number of a customer, " +
                                    "and then click the Find Customer Account button.",
                                    "Stellar Water Point", MessageBoxButtons.OK);
                    return;
                }
    
                string strCustomers = string.Empty;
                List<Customer> clients = new List<Customer>();
                string fileCustomers = @"C:\Stellar Water Point2\Customers.json";
    
                FileInfo fiCustomers = new FileInfo(fileCustomers);
    
                string? strMeterNumber = string.Empty;
    
                if (fiCustomers.Exists == true)
                {
                    using (TextReader trCustomers = new StreamReader(fiCustomers.FullName))
                    {
                        strCustomers = File.ReadAllText(fiCustomers.FullName);
                        clients = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
    
                        IEnumerable<Customer> customers = clients.Where(cust => cust.AccountNumber == mtbAccountNumber.Text);
    
                        foreach (Customer client in customers)
                        {
                            txtAccountName.Text = client.AccountName;
                            strMeterNumber      = client.MeterNumber;
                            txtAccountType.Text = client.AccountType;
                            txtAddress.Text     = client.Address;
                            txtCity.Text        = client.City;
                            txtCounty.Text      = client.County;
                            txtState.Text       = client.State;
                            txtZIPCode.Text     = client.ZIPCode;
                        }
                    }
                }
    
                if (strMeterNumber!.Length > 0)
                {
                    string strWaterMeters = string.Empty;
                    List<WaterMeter> waterMeters = new List<WaterMeter>();
                    string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
                    FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
                    if (fiWaterMeters.Exists == true)
                    {
                        strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
                        waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
    
                        IEnumerable<WaterMeter> meters = waterMeters.Where(wm => wm.MeterNumber == strMeterNumber);
    
                        foreach (WaterMeter meter in meters)
                        {
                            txtMeterDetails.Text = meter.Make + " " +
                                                   meter.Model +
                                                   " (Meter Size: " + meter.MeterSize + ")";
                        }
                    }
                }
            }
    
            private void dtpMeterReadingEndDate_ValueChanged(object sender, EventArgs e)
            {
                TimeSpan tsDays = dtpMeterReadingEndDate.Value - dtpMeterReadingStartDate.Value;
    
                txtBillingDays.Text = (tsDays.Days + 1).ToString();
            }
    
            private void btnEvaluateWaterBill_Click(object sender, EventArgs e)
            {
                double counterStart = 0, counterEnd = 0;
    
                try
                {
                    counterStart = double.Parse(txtCounterReadingStart.Text);
                }
                catch (FormatException feCRStart)
                {
                    MsgBox.Show("You must enter a valid value in the Counter Reading Start text box. " +
                                    "The error produced is: " + feCRStart.Message,
                                    "Stellar Water Point", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
    
                try
                {
                    counterEnd = double.Parse(txtCounterReadingEnd.Text);
                }
                catch (FormatException feCREnd)
                {
                    MsgBox.Show("You must enter a valid value in the Counter Reading End text box. " +
                                    "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 = WaterBillManager.CalculateTiers(strAccountType, gallons);
    
                double waterCharges           = tiers.first + tiers.second + tiers.last;
                double sewerCharges           = WaterBillManager.CalculateSewerCharges(strAccountType, waterCharges);
                double envCharges             = WaterBillManager.CalculateEnvironmentCharges(strAccountType, waterCharges);
                double srvCharges             = WaterBillManager.CalculateServiceCharges(strAccountType, waterCharges);
                double totalCharges           = waterCharges + sewerCharges + envCharges + srvCharges;
                double localTaxes             = WaterBillManager.CalculateLocalTaxes(strAccountType, waterCharges);
                double stateTaxes             = WaterBillManager.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       = WaterBillManager.SetPaymentDueDate(strAccountType, dtpMeterReadingEndDate.Value);
                txtAmountDue.Text             = amtDue.ToString("F");
                dtpLatePaymentDueDate.Value   = WaterBillManager.SetLatePaymentDueDate(strAccountType, dtpMeterReadingEndDate.Value);
                txtLateAmountDue.Text         = WaterBillManager.CalculateLateAmountDue(strAccountType, amtDue).ToString("F");
            }
    
            private void btnSaveWaterBill_Click(object sender, EventArgs e)
            {
                if (string.IsNullOrEmpty(txtBillNumber.Text))
                {
                    MsgBox.Show("You must type a (unique) bill number for the " +
                                    "water bill you are processing.",
                                    "Stellar Water Point", MessageBoxButtons.OK);
                    return;
                }
    
                if (string.IsNullOrEmpty(mtbAccountNumber.Text))
                {
                    MsgBox.Show("You must specify the account number of the customer " +
                                    "whose water bill you are preparing.",
                                    "Stellar Water Point", MessageBoxButtons.OK);
                    return;
                }
    
                string strWaterBills      = string.Empty;
                List<WaterBill> bills     = new List<WaterBill>();
                string fileWaterBills     = @"C:\Stellar Water Point2\WaterBills.json";
    
                FileInfo fiWaterBills     = new FileInfo(fileWaterBills);
    
                if (fiWaterBills.Exists   == true)
                {
                    strWaterBills         = File.ReadAllText(fiWaterBills.FullName);
                    bills                 = JsonSerializer.Deserialize<List<WaterBill>>(strWaterBills)!;
                }
    
                WaterBill bill            = new()
                {
                    BillNumber            = int.Parse(txtBillNumber.Text),
                    AccountNumber         = mtbAccountNumber.Text,
                    MeterReadingStartDate = dtpMeterReadingStartDate.Value,
                    MeterReadingEndDate   = dtpMeterReadingEndDate.Value,
                    BillingDays           = int.Parse(txtBillingDays.Text),
                    CounterReadingStart   = int.Parse(txtCounterReadingStart.Text),
                    CounterReadingEnd     = int.Parse(txtCounterReadingEnd.Text),
                    TotalHCF              = int.Parse(txtTotalHCF.Text),
                    TotalGallons          = int.Parse(txtTotalGallons.Text),
                    FirstTierConsumption  = double.Parse(txtFirstTierConsumption.Text),
                    SecondTierConsumption = double.Parse(txtSecondTierConsumption.Text),
                    LastTierConsumption   = double.Parse(txtLastTierConsumption.Text),
                    WaterCharges          = double.Parse(txtWaterCharges.Text),
                    SewerCharges          = double.Parse(txtSewerCharges.Text),
                    EnvironmentCharges    = double.Parse(txtEnvironmentCharges.Text),
                    ServiceCharges        = double.Parse(txtServiceCharges.Text),
                    TotalCharges          = double.Parse(txtTotalCharges.Text),
                    LocalTaxes            = double.Parse(txtLocalTaxes.Text),
                    StateTaxes            = double.Parse(txtStateTaxes.Text),
                    PaymentDueDate        = dtpPaymentDueDate.Value,
                    AmountDue             = double.Parse(txtAmountDue.Text),
                    LatePaymentDueDate    = dtpLatePaymentDueDate.Value,
                    LateAmountDue         = double.Parse(txtLateAmountDue.Text)
                };
    
                bills.Add(bill);
    
                JsonSerializerOptions options = new JsonSerializerOptions();
                options.WriteIndented = true;
    
                string jsWaterBills = JsonSerializer.Serialize(bills, typeof(List<WaterBill>), options);
                File.WriteAllText(fiWaterBills.FullName, jsWaterBills);
    
                Close();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  16. In the Solution Explorer, below the WaterBills folder, double-click Central.cs
  17. From the Toolbox, add a button to the form below the list view
  18. Change the characteristics of the button as follows:

    Stellar Water Point - Water Meters

    Control (Name) Other Properties
    ListView List View lvwWaterBills No Change
    Button Button btnProcessWaterBill &Process Water Bill...
  19. On the Central form, double-click the Process Water Bill button
  20. Implement the event as follows:
    using System.Data;
    using Microsoft.Data.SqlClient;
    
    namespace StellarWaterPoint21.WaterBills
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowWaterBills()
            {
                . . .
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                ShowWaterBills();
            }
    
            private void btnProcessWaterBill_Click(object sender, EventArgs e)
            {
                Create create = new();
    
                create.ShowDialog();
    
                ShowWaterBills();
            }
        }
    }
  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 Bills button:

    Stellar Water Point - Water Bills

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

    Stellar Water Point - Create Water Bill

  24. 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 - Water Bills

  25. Close the forms and return to your programming environment

Water Bill Details

Sometimes, an employee just wants to view the information that is related to a water bill. We will create a form to make it possible.

Practical LearningPractical Learning: Showing a Water Bill

  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 Water Bill

    Control Text Name Enabled
    Label Label &Water Bill #:    
    TextBox Text Box   txtBillNumber  
    Button Button &Find Water Bill btnFindWaterBill  
    GroupBox Group Box Customer Information    
    Label Label &Account #:    
    TextBox Text Box   txtAccountNumber False
    Label Label Account Name:    
    TextBox Text Box   txtAccountName False
    Label Label Account Type:    
    TextBox Text Box   txtAccountType  
    Label Label Address:   False
    TextBox Text Box   txtAddress False
    TextBox Text Box   txtCity  
    TextBox Text Box   txtCounty False
    TextBox Text Box   txtState False
    TextBox Text Box   txtZIPCode False
    Label Label _______________________________    
    Label Label Meter Details:    
    TextBox Text Box   txtMeterDetails False
    GroupBox Group Box Meter Reading    
    Label Label Meter &Reading Start Date:    
    Text Box Text Box   txtMeterReadingStartDate False
    Label Label Meter Reading &End Date:    
    Text Box Text Box   txtMeterReadingEndDate False
    Label Label Coun&ter Reading Start:    
    TextBox Text Box   txtCounterReadingStart False
    Label Label Counter Readi&ng End:    
    TextBox Text Box   txtCounterReadingEnd False
    GroupBox Group Box Meter Result    
    Label Label Billing Days:    
    TextBox Text Box   txtBillingDays False
    Label Label Total HCF:    
    TextBox Text Box   txtTotalHCF False
    Label Label Total Gallons:    
    TextBox Text Box   txtTotalGallons False
    Label Label First Tier Consumption:    
    TextBox Text Box   txtFirstTierConsumption False
    Label Label Second Tier:    
    TextBox Text Box   txtSecondTierConsumption False
    Label Label Last Tier:    
    TextBox Text Box   txtLastTierConsumption False
    GroupBox Group Box Consumption Charges    
    Label Label Water Charges:    
    TextBox Text Box   txtWaterCharges False
    Label Label Sewer Charges:    
    TextBox Text Box   txtSewerCharges False
    Label Label Environment Charges:    
    TextBox Text Box   txtEnvironmentCharges False
    Label Label Service Charges:    
    TextBox Text Box   txtServiceCharges False
    Label Label Total Charges:    
    TextBox Text Box   txtTotalCharges False
    GroupBox Group Box Taxes    
    Label Label Local Taxes:    
    TextBox Text Box   txtLocalTaxes False
    Label Label State Taxes:    
    TextBox Text Box   txtStateTaxes False
    GroupBox Group Box Water Bill Payment    
    Label Label Payment Due Date:    
    Date Time Picker Text Box   dtpPaymentDueDate False
    Label Label Amount Due:    
    TextBox Text Box   txtAmountDue False
    Label Label Late Payment Due Date:    
    Text Box Text Box   txtLatePaymentDueDate False
    Label Label &Late Amount Due:    
    TextBox Text Box   txtLateAmountDue  
    Label Label Water Bill Id:    
    TextBox Text Box   txtWaterBillId False
    Button Button &Close btnClose  

    Form Properties

    Form Property Value
    FormBorderStyle FixedDialog
    Text Stellar Water Point - Water Bill Details
    StartPosition CenterScreen
    MaximizeBox False
    MinimizeBox False
  5. On the form, double-click the Find Water Bill button
  6. Change the document as follows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.WaterBills
    {
        public partial class Details : Form
        {
            public Details()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterBill_Click(object sender, EventArgs e)
            {
                string strWaterBills = string.Empty;
                List<WaterBill> bills = new List<WaterBill>();
                string fileWaterBills = @"C:\Stellar Water Point2\WaterBills.json";
    
                FileInfo fiWaterBills = new FileInfo(fileWaterBills);
    
                string strAccountsTypes = string.Empty;
                List<AccountType> accountsTypes = new List<AccountType>();
                string fileAccountsTypes = @"C:\Stellar Water Point2\AccountsTypes.json";
    
                FileInfo fiAccountsTypes = new FileInfo(fileAccountsTypes);
    
                if (fiWaterBills.Exists == true)
                {
                    using (TextReader trWaterBills = new StreamReader(fiWaterBills.FullName))
                    {
                        strWaterBills = File.ReadAllText(fiWaterBills.FullName);
                        bills = JsonSerializer.Deserialize<List<WaterBill>>(strWaterBills)!;
    
                        IEnumerable<WaterBill> selected = bills.Where(wb => wb.BillNumber == int.Parse(txtBillNumber.Text));
    
                        foreach (var bill in selected)
                        {
                            txtWaterBillId.Text = bill.WaterBillId.ToString();
                            txtAccountNumber.Text = bill.AccountNumber;
                            txtMeterReadingStartDate.Text = bill.MeterReadingStartDate.ToLongDateString();
                            txtMeterReadingEndDate.Text = bill.MeterReadingEndDate.ToLongDateString();
                            txtBillingDays.Text = bill.BillingDays.ToString();
                            txtCounterReadingStart.Text = bill.CounterReadingStart.ToString();
                            txtCounterReadingEnd.Text = bill.CounterReadingEnd.ToString();
                            txtTotalHCF.Text = bill.TotalHCF.ToString();
                            txtTotalGallons.Text = bill.TotalGallons.ToString();
                            txtFirstTierConsumption.Text = bill.FirstTierConsumption.ToString();
                            txtSecondTierConsumption.Text = bill.SecondTierConsumption.ToString();
                            txtLastTierConsumption.Text = bill.LastTierConsumption.ToString();
                            txtWaterCharges.Text = bill.WaterCharges.ToString();
                            txtSewerCharges.Text = bill.SewerCharges.ToString();
                            txtEnvironmentCharges.Text = bill.EnvironmentCharges.ToString();
                            txtServiceCharges.Text = bill.ServiceCharges.ToString();
                            txtTotalCharges.Text = bill.TotalCharges.ToString();
                            txtLocalTaxes.Text = bill.LocalTaxes.ToString();
                            txtStateTaxes.Text = bill.StateTaxes.ToString();
                            txtPaymentDueDate.Text = bill.PaymentDueDate.ToLongDateString();
                            txtAmountDue.Text = bill.AmountDue.ToString();
                            txtLatePaymentDueDate.Text = bill.LatePaymentDueDate.ToLongDateString();
                            txtLateAmountDue.Text = bill.LateAmountDue.ToString();
                        }
                    }
                }
    
                string strCustomers = string.Empty;
                List<Customer> clients = new List<Customer>();
                string fileCustomers = @"C:\Stellar Water Point2\Customers.json";
    
                FileInfo fiCustomers = new FileInfo(fileCustomers);
    
                string? strMeterNumber = string.Empty;
    
                string strAccountType = string.Empty;
    
                if (fiCustomers.Exists == true)
                {
                    using (TextReader trCustomers = new StreamReader(fiCustomers.FullName))
                    {
                        strCustomers = File.ReadAllText(fiCustomers.FullName);
                        clients = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
    
                        IEnumerable<Customer> customers = from consumer
                                                          in clients
                                                          where consumer.AccountNumber == txtAccountNumber.Text
                                                          select consumer;
    
                        foreach (Customer client in customers)
                        {
                            txtAccountName.Text = client.AccountName;
                            strMeterNumber = client.MeterNumber;
    
                            TextReader trAccountsTypess = new StreamReader(fiAccountsTypes.FullName);
                            strAccountsTypes = File.ReadAllText(fiAccountsTypes.FullName);
                            accountsTypes = JsonSerializer.Deserialize<List<AccountType>>(strAccountsTypes)!;
    
                            foreach (AccountType at in accountsTypes)
                            {
                                if (client.AccountType == at.TypeCode)
                                {
                                    txtAccountType.Text = string.Concat(at.TypeCode, " - ", at.TypeDecription);
                                }
                            }
    
                            txtAddress.Text = client.Address;
                            txtCity.Text = client.City;
                            txtCounty.Text = client.County;
                            txtState.Text = client.State;
                            txtZIPCode.Text = client.ZIPCode;
                        }
                    }
                }
    
                if (strMeterNumber!.Length > 0)
                {
                    string strWaterMeters = string.Empty;
                    List<WaterMeter> waterMeters = new List<WaterMeter>();
                    string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
                    FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
                    if (fiWaterMeters.Exists == true)
                    {
                        strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
                        waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
    
                        IEnumerable<WaterMeter> meters = from measure
                                                         in waterMeters
                                                         where measure.MeterNumber == strMeterNumber
                                                         select measure;
    
                        foreach (WaterMeter meter in waterMeters)
                        {
                            txtMeterDetails.Text = meter.Make + " " +
                                                   meter.Model +
                                                   " (Meter Size: " + meter.MeterSize + ")";
                        }
                    }
                }
            }
        }
    }
  7. Return to the form and double-click the Close button
  8. Implement the event as follows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.WaterBills
    {
        public partial class Details : Form
        {
            public Details()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterBill_Click(object sender, EventArgs e)
            {
                string strWaterBills = string.Empty;
                // Prepare a bills list to hold the records of water bills
                List<WaterBill> bills = new List<WaterBill>();
                // Specify the file that holds the records of water bills
                string fileWaterBills = @"C:\Stellar Water Point2\WaterBills.json";
    
                // Create a FileInfo object for the records of water bills
                FileInfo fiWaterBills = new FileInfo(fileWaterBills);
    
                // Find out whether a file that holds the records of water bills exists already
                if (fiWaterBills.Exists == true)
                {
                    // If that file exists, create a TextReader object to read the file
                    using (TextReader trWaterBills = new StreamReader(fiWaterBills.FullName))
                    {
                        /* Read the contents of the file that holds the water bills.
                         * Store the read text in the strWaterBills variable that was declared. */
                        strWaterBills = File.ReadAllText(fiWaterBills.FullName);
                        // Get the water bills and store them in the bills list variable
                        bills = JsonSerializer.Deserialize<List<WaterBill>>(strWaterBills)!;
    
                        IEnumerable<WaterBill> selected = bills.Where(wb => wb.BillNumber == int.Parse(txtBillNumber.Text));
    
                        foreach (var bill in selected)
                        {
                            txtAccountNumber.Text = bill.AccountNumber;
                            txtMeterReadingStartDate.Text = bill.MeterReadingStartDate.ToLongDateString();
                            txtMeterReadingEndDate.Text = bill.MeterReadingEndDate.ToLongDateString();
                            txtBillingDays.Text = bill.BillingDays.ToString();
                            txtCounterReadingStart.Text = bill.CounterReadingStart.ToString();
                            txtCounterReadingEnd.Text = bill.CounterReadingEnd.ToString();
                            txtTotalHCF.Text = bill.TotalHCF.ToString();
                            txtTotalGallons.Text = bill.TotalGallons.ToString();
                            txtFirstTierConsumption.Text = bill.FirstTierConsumption.ToString();
                            txtSecondTierConsumption.Text = bill.SecondTierConsumption.ToString();
                            txtLastTierConsumption.Text = bill.LastTierConsumption.ToString();
                            txtWaterCharges.Text = bill.WaterCharges.ToString();
                            txtSewerCharges.Text = bill.SewerCharges.ToString();
                            txtEnvironmentCharges.Text = bill.EnvironmentCharges.ToString();
                            txtServiceCharges.Text = bill.ServiceCharges.ToString();
                            txtTotalCharges.Text = bill.TotalCharges.ToString();
                            txtLocalTaxes.Text = bill.LocalTaxes.ToString();
                            txtStateTaxes.Text = bill.StateTaxes.ToString();
                            txtPaymentDueDate.Text = bill.PaymentDueDate.ToLongDateString();
                            txtAmountDue.Text = bill.AmountDue.ToString();
                            txtLatePaymentDueDate.Text = bill.LatePaymentDueDate.ToLongDateString();
                            txtLateAmountDue.Text = bill.LateAmountDue.ToString();
                        }
                    }
                }
    
                string strCustomers = string.Empty;
                List<Customer> clients = new List<Customer>();
                string fileCustomers = @"C:\Stellar Water Point2\Customers.json";
    
                FileInfo fiCustomers = new FileInfo(fileCustomers);
    
                string? strMeterNumber = string.Empty;
    
                if (fiCustomers.Exists == true)
                {
                    using (TextReader trCustomers = new StreamReader(fiCustomers.FullName))
                    {
                        strCustomers = File.ReadAllText(fiCustomers.FullName);
                        clients = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
    
                        IEnumerable<Customer> customers = from consumer
                                                          in clients
                                                          where consumer.AccountNumber == txtAccountNumber.Text
                                                          select consumer;
    
                        foreach (Customer client in customers)
                        {
                            txtAccountName.Text = client.AccountName;
                            strMeterNumber = client.MeterNumber;
                            txtAccountType.Text = client.AccountType;
                            txtAddress.Text = client.Address;
                            txtCity.Text = client.City;
                            txtCounty.Text = client.County;
                            txtState.Text = client.State;
                            txtZIPCode.Text = client.ZIPCode;
                        }
                    }
                }
    
                if (strMeterNumber!.Length > 0)
                {
                    string strWaterMeters = string.Empty;
                    List<WaterMeter> waterMeters = new List<WaterMeter>();
                    string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
                    FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
                    if (fiWaterMeters.Exists == true)
                    {
                        strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
                        waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
    
                        IEnumerable<WaterMeter> meters = from measure
                                                         in waterMeters
                                                         where measure.MeterNumber == strMeterNumber
                                                         select measure;
    
                        foreach (WaterMeter meter in waterMeters)
                        {
                            txtMeterDetails.Text = meter.Make + " " +
                                                   meter.Model +
                                                   " (Meter Size: " + meter.MeterSize + ")";
                        }
                    }
                }
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  9. In the Solution Explorer, below the WaterBills folder, double-click Central.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 New Water Bill button
  11. Change the characteristics of the button as follows:

    Stellar Water Point - Water Meters

    Control (Name) Other Properties
    ListView List View lvwWaterBills No Change
    Button Button No Change No Change
    Button Button btnWaterBillDetails Water Bill &Details...
  12. Double-click the Water Bill &Details button
  13. Change the document as follows:
    using System.Data;
    using Microsoft.Data.SqlClient;
    
    namespace StellarWaterPoint21.WaterBills
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowWaterBills()
            {
                . . .
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                ShowWaterBills();
            }
    
            private void btnProcessWaterBill_Click(object sender, EventArgs e)
            {
                Create create = new();
    
                create.ShowDialog();
    
                ShowWaterBills();
            }
    
            private void btnViewWaterBill_Click(object sender, EventArgs e)
            {
                Details details = new();
    
                details.Show();
            }
        }
    }
  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
  18. Click the Find Water Bill button:

    Stellar Water Point - View Water Bill

  19. Close the forms and return to your programming environment

Water Bill Edition

If some aspect of a water bill changes, we will create a form that an employee can use to update the record.

Practical LearningPractical Learning: Creating a Water Bill Editor

  1. In the Solution Explorer, right-click the WaterBills folder -> Add -> Form (Windows Forms...)
  2. Set the name of the form to Editor
  3. Click Add
  4. Using the Properties window, change the size of the new form to match the size of the Process Water Bill form
  5. Select everything in the Process Water Bill form and copy it
  6. Paste it in Water Bill Editor form
  7. Change the design of the Water Bill Editor form as follows (you will add only the controls that are not found in the New Water Bill form):

    Stellar Water Point - Water Bill Editor

    Control (Name) Text
    Button Button btnFindWaterBill &Find Water Bill
    Button Button btnUpdateWaterBill &Update Water Bill
  8. On the form, double-click Find Water Bill button
  9. Change the document as follows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.WaterBills
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterBill_Click(object sender, EventArgs e)
            {
                string strWaterBills     = string.Empty;
                List<WaterBill> bills    = new List<WaterBill>();
                string fileWaterBills    = @"C:\Stellar Water Point2\WaterBills.json";
    
                FileInfo fiWaterBills    = new FileInfo(fileWaterBills);
    
                string strAccountsTypes  = string.Empty;
                List<AccountType> accountsTypes = new List<AccountType>();
                string fileAccountsTypes = @"C:\Stellar Water Point2\AccountsTypes.json";
    
                FileInfo fiAccountsTypes = new FileInfo(fileAccountsTypes);
    
                if (fiWaterBills.Exists  == true)
                {
                    using (TextReader trWaterBills = new StreamReader(fiWaterBills.FullName))
                    {
                        strWaterBills    = File.ReadAllText(fiWaterBills.FullName);
                        bills            = JsonSerializer.Deserialize<List<WaterBill>>(strWaterBills)!;
    
                        IEnumerable<WaterBill> selected = bills.Where(wb => wb.BillNumber == int.Parse(txtWaterBillNumber.Text));
    
                        foreach (var bill in selected)
                        {
                            txtWaterBillId.Text            = bill.WaterBillId.ToString();
                            mtbAccountNumber.Text          = bill.AccountNumber;
                            dtpMeterReadingStartDate.Value = bill.MeterReadingStartDate;
                            dtpMeterReadingEndDate.Value   = bill.MeterReadingEndDate;
                            txtBillingDays.Text            = bill.BillingDays.ToString();
                            txtCounterReadingStart.Text    = bill.CounterReadingStart.ToString();
                            txtCounterReadingEnd.Text      = bill.CounterReadingEnd.ToString();
                            txtTotalHCF.Text               = bill.TotalHCF.ToString();
                            txtTotalGallons.Text           = bill.TotalGallons.ToString();
                            txtFirstTierConsumption.Text   = bill.FirstTierConsumption.ToString();
                            txtSecondTierConsumption.Text  = bill.SecondTierConsumption.ToString();
                            txtLastTierConsumption.Text    = bill.LastTierConsumption.ToString();
                            txtWaterCharges.Text           = bill.WaterCharges.ToString();
                            txtSewerCharges.Text           = bill.SewerCharges.ToString();
                            txtEnvironmentCharges.Text     = bill.EnvironmentCharges.ToString();
                            txtServiceCharges.Text         = bill.ServiceCharges.ToString();
                            txtTotalCharges.Text           = bill.TotalCharges.ToString();
                            txtLocalTaxes.Text             = bill.LocalTaxes.ToString();
                            txtStateTaxes.Text             = bill.StateTaxes.ToString();
                            dtpPaymentDueDate.Value        = bill.PaymentDueDate;
                            txtAmountDue.Text              = bill.AmountDue.ToString();
                            dtpLatePaymentDueDate.Value    = bill.LatePaymentDueDate;
                            txtLateAmountDue.Text          = bill.LateAmountDue.ToString();
                        }
                    }
                }
    
                string strCustomers = string.Empty;
                List<Customer> clients = new List<Customer>();
                string fileCustomers = @"C:\Stellar Water Point2\Customers.json";
    
                FileInfo fiCustomers = new FileInfo(fileCustomers);
    
                string? strMeterNumber = string.Empty;
    
                string strAccountType = string.Empty;
    
                if (fiCustomers.Exists == true)
                {
                    using (TextReader trCustomers = new StreamReader(fiCustomers.FullName))
                    {
                        strCustomers = File.ReadAllText(fiCustomers.FullName);
                        clients = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
    
                        IEnumerable<Customer> customers = from consumer
                                                          in clients
                                                          where consumer.AccountNumber == mtbAccountNumber.Text
                                                          select consumer;
    
                        foreach (Customer client in customers)
                        {
                            txtAccountName.Text = client.AccountName;
                            strMeterNumber = client.MeterNumber;
    
                            TextReader trAccountsTypess = new StreamReader(fiAccountsTypes.FullName);
                            strAccountsTypes = File.ReadAllText(fiAccountsTypes.FullName);
                            accountsTypes = JsonSerializer.Deserialize<List<AccountType>>(strAccountsTypes)!;
    
                            foreach (AccountType at in accountsTypes)
                            {
                                if (client.AccountType == at.TypeCode)
                                {
                                    txtAccountType.Text = string.Concat(at.TypeCode, " - ", at.TypeDecription);
                                }
                            }
    
                            txtAddress.Text = client.Address;
                            txtCity.Text = client.City;
                            txtCounty.Text = client.County;
                            txtState.Text = client.State;
                            txtZIPCode.Text = client.ZIPCode;
                        }
                    }
                }
    
                if (strMeterNumber!.Length > 0)
                {
                    string strWaterMeters = string.Empty;
                    List<WaterMeter> waterMeters = new List<WaterMeter>();
                    string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
                    FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
                    if (fiWaterMeters.Exists == true)
                    {
                        strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
                        waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
    
                        IEnumerable<WaterMeter> meters = from measure
                                                         in waterMeters
                                                         where measure.MeterNumber == strMeterNumber
                                                         select measure;
    
                        foreach (WaterMeter meter in waterMeters)
                        {
                            txtMeterDetails.Text = meter.Make + " " +
                                                   meter.Model +
                                                   " (Meter Size: " + meter.MeterSize + ")";
                        }
                    }
                }
            }
        }
    }
  10. Return to the form and double-click the Find Customer Account button
  11. Implement the event as follows:
    private void btnFindCustomerAccount_Click(object sender, EventArgs e)
    {
        string strAccountNumber = mtbAccountNumber.Text.Replace("-", "").Trim();
    
        if (string.IsNullOrEmpty(strAccountNumber))
        {
            MsgBox.Show("You must type a valid account number of a customer, " +
                            "and then click the Find Customer Account button.");
            return;
        }
    
        string strCustomers = string.Empty;
        List<Customer> clients = new List<Customer>();
        string fileCustomers = @"C:\Stellar Water Point2\Customers.json";
    
        FileInfo fiCustomers = new FileInfo(fileCustomers);
    
        string strAccountsTypes = string.Empty;
        List<AccountType> accountsTypes = new List<AccountType>();
        string fileAccountsTypes = @"C:\Stellar Water Point2\AccountsTypes.json";
    
        FileInfo fiAccountsTypes = new FileInfo(fileAccountsTypes);
    
        string? strMeterNumber = string.Empty;
    
        if (fiCustomers.Exists == true)
        {
            using (TextReader trCustomers = new StreamReader(fiCustomers.FullName))
            {
                strCustomers = File.ReadAllText(fiCustomers.FullName);
                clients = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
    
                IEnumerable<Customer> customers = clients.Where(cust => cust.AccountNumber == mtbAccountNumber.Text);
    
                foreach (Customer client in customers)
                {
                    txtAccountName.Text = client.AccountName;
                    strMeterNumber = client.MeterNumber;
    
                    TextReader trAccountsTypess = new StreamReader(fiAccountsTypes.FullName);
                    strAccountsTypes = File.ReadAllText(fiAccountsTypes.FullName);
                    accountsTypes = JsonSerializer.Deserialize<List<AccountType>>(strAccountsTypes)!;
    
                    foreach (AccountType at in accountsTypes)
                    {
                        if (client.AccountType == at.TypeCode)
                        {
                            txtAccountType.Text = string.Concat(at.TypeCode, " - ", at.TypeDecription);
                        }
                    }
    
                    txtAddress.Text = client.Address;
                    txtCity.Text = client.City;
                    txtCounty.Text = client.County;
                    txtState.Text = client.State;
                    txtZIPCode.Text = client.ZIPCode;
                }
            }
        }
    
        if (strMeterNumber!.Length > 0)
        {
            string strWaterMeters = string.Empty;
            List<WaterMeter> waterMeters = new List<WaterMeter>();
            string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
            FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
            if (fiWaterMeters.Exists == true)
            {
                strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
                waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
    
                IEnumerable<WaterMeter> meters = waterMeters.Where(wm => wm.MeterNumber == strMeterNumber);
    
                foreach (WaterMeter meter in meters)
                {
                    txtMeterDetails.Text = meter.WaterMeterId.ToString() + " - " +
                                           meter.Make + " " +
                                           meter.Model +
                                           " (Meter Size: " + meter.MeterSize + ")";
                }
            }
        }
    }
  12. Return to the form and double-click the Meter Reading End Date date time picker control
  13. Implement the event as follows:
    private void dtpMeterReadingEndDate_ValueChanged(object sender, EventArgs e)
    {
        TimeSpan tsDays = dtpMeterReadingEndDate.Value - dtpMeterReadingStartDate.Value;
    
        txtBillingDays.Text = (tsDays.Days + 1).ToString();
    }
  14. Return to the form and double-click the Evaluate Water Bill button
  15. Implement the event as follows:
    private void btnEvaluateWaterBill_Click(object sender, EventArgs e)
    {
        double counterStart = 0, counterEnd = 0;
    
        try
        {
            counterStart = double.Parse(txtCounterReadingStart.Text);
        }
        catch (FormatException feCRStart)
        {
            MsgBox.Show("You must enter a valid value in the Counter Reading Start text box. " +
                            "The error produced is: " + feCRStart.Message);
        }
    
        try
        {
            counterEnd = double.Parse(txtCounterReadingEnd.Text);
        }
        catch (FormatException feCREnd)
        {
            MsgBox.Show("You must enter a valid value in the Counter Reading End text box. " +
                            "The error produced is: " + feCREnd.Message);
        }
    
        double consumption = counterEnd - counterStart;
        double gallons = consumption * 748.05;
        string strAccountType = txtAccountType.Text[..3];
    
        (double first, double second, double last) tiers = WaterBillManager.CalculateTiers(strAccountType, gallons);
    
        double waterCharges = tiers.first + tiers.second + tiers.last;
        double sewerCharges = WaterBillManager.CalculateSewerCharges(strAccountType, waterCharges);
        double envCharges = WaterBillManager.CalculateEnvironmentCharges(strAccountType, waterCharges);
        double srvCharges = WaterBillManager.CalculateServiceCharges(strAccountType, waterCharges);
        double totalCharges = waterCharges + sewerCharges + envCharges + srvCharges;
        double localTaxes = WaterBillManager.CalculateLocalTaxes(strAccountType, waterCharges);
        double stateTaxes = WaterBillManager.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 = WaterBillManager.SetPaymentDueDate(strAccountType, dtpMeterReadingEndDate.Value);
        txtAmountDue.Text = amtDue.ToString("F");
        dtpLatePaymentDueDate.Value = WaterBillManager.SetLatePaymentDueDate(strAccountType, dtpMeterReadingEndDate.Value);
        txtLateAmountDue.Text = WaterBillManager.CalculateLateAmountDue(strAccountType, amtDue).ToString("F");
    }
  16. Return to the form and double-click the Update Water Bill button
  17. Change the document as follows:
    private void btnUpdateWaterBill_Click(object sender, EventArgs e)
    {
        if (string.IsNullOrEmpty(txtWaterBillNumber.Text))
        {
            MsgBox.Show("You must provide the bill number of the " +
                        "water bill you are trying to update.");
            return;
        }
    
        if (string.IsNullOrEmpty(mtbAccountNumber.Text))
        {
            MsgBox.Show("Please make sure you provide the account number of the customer " +
                        "associated with the water bill you are trying to update.");
            return;
        }
    
        string strWaterBills = string.Empty;
        List<WaterBill> bills = new List<WaterBill>();
        string fileWaterBills = @"C:\Stellar Water Point2\WaterBills.json";
    
        FileInfo fiWaterBills = new FileInfo(fileWaterBills);
    
        if (fiWaterBills.Exists == true)
        {
            strWaterBills = File.ReadAllText(fiWaterBills.FullName);
            bills = JsonSerializer.Deserialize<List<WaterBill>>(strWaterBills)!;
    
            WaterBill? bill = bills.Find(invoice => invoice.BillNumber == int.Parse(txtWaterBillNumber.Text));
    
            if (bill is not null)
            {
                bill.WaterBillId = int.Parse(txtWaterBillId.Text);
                bill.BillNumber = int.Parse(txtWaterBillNumber.Text);
                bill.AccountNumber = mtbAccountNumber.Text;
                bill.MeterReadingStartDate = dtpMeterReadingStartDate.Value;
                bill.MeterReadingEndDate = dtpMeterReadingEndDate.Value;
                bill.BillingDays = int.Parse(txtBillingDays.Text);
                bill.CounterReadingStart = int.Parse(txtCounterReadingStart.Text);
                bill.CounterReadingEnd = int.Parse(txtCounterReadingEnd.Text);
                bill.TotalHCF = int.Parse(txtTotalHCF.Text);
                bill.TotalGallons = int.Parse(txtTotalGallons.Text);
                bill.FirstTierConsumption = double.Parse(txtFirstTierConsumption.Text);
                bill.SecondTierConsumption = double.Parse(txtSecondTierConsumption.Text);
                bill.LastTierConsumption = double.Parse(txtLastTierConsumption.Text);
                bill.WaterCharges = double.Parse(txtWaterCharges.Text);
                bill.SewerCharges = double.Parse(txtSewerCharges.Text);
                bill.EnvironmentCharges = double.Parse(txtEnvironmentCharges.Text);
                bill.ServiceCharges = double.Parse(txtServiceCharges.Text);
                bill.TotalCharges = double.Parse(txtTotalCharges.Text);
                bill.LocalTaxes = double.Parse(txtLocalTaxes.Text);
                bill.StateTaxes = double.Parse(txtStateTaxes.Text);
                bill.PaymentDueDate = dtpPaymentDueDate.Value;
                bill.AmountDue = double.Parse(txtAmountDue.Text);
                bill.LatePaymentDueDate = dtpLatePaymentDueDate.Value;
                bill.LateAmountDue = double.Parse(txtLateAmountDue.Text);
    
                JsonSerializerOptions options = new JsonSerializerOptions();
                options.WriteIndented = true;
    
                string jsWaterBills = JsonSerializer.Serialize(bills, typeof(List<WaterBill>), options);
                File.WriteAllText(fiWaterBills.FullName, jsWaterBills);
            }
        }
    
        Close();
    }
  18. Return to the form and double-click the Close button
  19. Change the document as follows:
    private void btnClose_Click(object sender, EventArgs e)
    {
        Close();
    }
  20. In the Solution Explorer, below the WaterBills folder, double-click Central.cs
  21. From the Toolbox, add a button to the form below the list view and on the right side of the View Water Bill button
  22. Change the characteristics of the button as follows:

    Stellar Water Point - Water Meters

    Control (Name) Text
    ListView List View lvwWaterBills  
    Button Button btnNewWaterBill  
    Button Button btnViewWaterBill  
    Button Button btnEditWaterBill &Edit Water Bill...
  23. Double-click the Edit Water Bill button
  24. Implement the event as follows:
    private void btnWaterBillEditor_Click(object sender, EventArgs e)
    {
        Editor update = new Editor();
    
        update.ShowDialog();
        
        ShowWaterBills();
    }
  25. To execute the application, on the main menu, click Debug -> Start Without Debugging

    Stellar Water Point

  26. On the main form of the application, click the Water Bills button:

    Stellar Water Point - Water Bills

  27. Click the Edit Water Bill button:

    Stellar Water Point - Water Bill Editor

  28. In the Water Bill # text, type 923633
  29. Click the Find Water Bill button

    Stellar Water Point - Water Bill Editor

  30. 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
  31. Click the Evaluate Water Bill button:

    Stellar Water Point - Water Bill Editor

  32. Click the Update Water Bill button and click OK on the message box:

    Stellar Water Point - Water Bills

  33. Close the forms and return to your programming environment

Water Bill Deletion

If a water bill is useless and must not be kept as a record in the system, an employee must be able to delete it. We will create a form that makes it possible to delete a water bill.

Practical LearningPractical Learning: Deleting a Water Bill Record

  1. To create a form, in the Solution Explorer, right-click the WaterBills folder -> Add -> Form (Windows Forms...)
  2. Change the file Name to Delete
  3. Click Add Resize the form to have the same size as the Water Bill Details form
  4. Select and copy everything in the Water Bill Details form
  5. Paste it in the new Water Bill Delete form
  6. Change the design of the form as follows (you will add only one button):

    Stellar Water Point - Water Bill Deletion

    Control (Name) Text
    Button Button btnDeleteWaterBill &Delete Water Bill
  7. On the form, double-click the Find Water Bill button
  8. Change the document as follows:
    using System.Data;
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.WaterBills
    {
        public partial class Delete : Form
        {
            public Delete()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterBill_Click(object sender, EventArgs e)
            {
                string strWaterBills = string.Empty;
                List<WaterBill> bills = new List<WaterBill>();
                string fileWaterBills = @"C:\Stellar Water Point2\WaterBills.json";
    
                FileInfo fiWaterBills = new FileInfo(fileWaterBills);
    
                string strAccountsTypes = string.Empty;
                List<AccountType> accountsTypes = new List<AccountType>();
                string fileAccountsTypes = @"C:\Stellar Water Point2\AccountsTypes.json";
    
                FileInfo fiAccountsTypes = new FileInfo(fileAccountsTypes);
    
                if (fiWaterBills.Exists == true)
                {
                    using (TextReader trWaterBills = new StreamReader(fiWaterBills.FullName))
                    {
                        strWaterBills = File.ReadAllText(fiWaterBills.FullName);
                        bills = JsonSerializer.Deserialize<List<WaterBill>>(strWaterBills)!;
    
                        IEnumerable<WaterBill> selected = bills.Where(wb => wb.BillNumber == int.Parse(txtWaterBillNumber.Text));
    
                        foreach (var bill in selected)
                        {
                            txtWaterBillId.Text = bill.WaterBillId.ToString();
                            txtAccountNumber.Text = bill.AccountNumber;
                            txtMeterReadingStartDate.Text = bill.MeterReadingStartDate.ToLongDateString();
                            txtMeterReadingEndDate.Text = bill.MeterReadingEndDate.ToLongDateString();
                            txtBillingDays.Text = bill.BillingDays.ToString();
                            txtCounterReadingStart.Text = bill.CounterReadingStart.ToString();
                            txtCounterReadingEnd.Text = bill.CounterReadingEnd.ToString();
                            txtTotalHCF.Text = bill.TotalHCF.ToString();
                            txtTotalGallons.Text = bill.TotalGallons.ToString();
                            txtFirstTierConsumption.Text = bill.FirstTierConsumption.ToString();
                            txtSecondTierConsumption.Text = bill.SecondTierConsumption.ToString();
                            txtLastTierConsumption.Text = bill.LastTierConsumption.ToString();
                            txtWaterCharges.Text = bill.WaterCharges.ToString();
                            txtSewerCharges.Text = bill.SewerCharges.ToString();
                            txtEnvironmentCharges.Text = bill.EnvironmentCharges.ToString();
                            txtServiceCharges.Text = bill.ServiceCharges.ToString();
                            txtTotalCharges.Text = bill.TotalCharges.ToString();
                            txtLocalTaxes.Text = bill.LocalTaxes.ToString();
                            txtStateTaxes.Text = bill.StateTaxes.ToString();
                            txtPaymentDueDate.Text = bill.PaymentDueDate.ToLongDateString();
                            txtAmountDue.Text = bill.AmountDue.ToString();
                            txtLatePaymentDueDate.Text = bill.LatePaymentDueDate.ToLongDateString();
                            txtLateAmountDue.Text = bill.LateAmountDue.ToString();
                        }
                    }
                }
    
                string strCustomers = string.Empty;
                List<Customer> clients = new List<Customer>();
                string fileCustomers = @"C:\Stellar Water Point2\Customers.json";
    
                FileInfo fiCustomers = new FileInfo(fileCustomers);
    
                string? strMeterNumber = string.Empty;
    
                string strAccountType = string.Empty;
    
                if (fiCustomers.Exists == true)
                {
                    using (TextReader trCustomers = new StreamReader(fiCustomers.FullName))
                    {
                        strCustomers = File.ReadAllText(fiCustomers.FullName);
                        clients = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
    
                        IEnumerable<Customer> customers = from consumer
                                                          in clients
                                                          where consumer.AccountNumber == txtAccountNumber.Text
                                                          select consumer;
    
                        foreach (Customer client in customers)
                        {
                            txtAccountName.Text = client.AccountName;
                            strMeterNumber = client.MeterNumber;
    
                            TextReader trAccountsTypess = new StreamReader(fiAccountsTypes.FullName);
                            strAccountsTypes = File.ReadAllText(fiAccountsTypes.FullName);
                            accountsTypes = JsonSerializer.Deserialize<List<AccountType>>(strAccountsTypes)!;
    
                            foreach (AccountType at in accountsTypes)
                            {
                                if (client.AccountType == at.TypeCode)
                                {
                                    txtAccountType.Text = string.Concat(at.TypeCode, " - ", at.TypeDecription);
                                }
                            }
    
                            txtAddress.Text = client.Address;
                            txtCity.Text = client.City;
                            txtCounty.Text = client.County;
                            txtState.Text = client.State;
                            txtZIPCode.Text = client.ZIPCode;
                        }
                    }
                }
    
                if (strMeterNumber!.Length > 0)
                {
                    string strWaterMeters = string.Empty;
                    List<WaterMeter> waterMeters = new List<WaterMeter>();
                    string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
                    FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
                    if (fiWaterMeters.Exists == true)
                    {
                        strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
                        waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
    
                        IEnumerable<WaterMeter> meters = from measure
                                                         in waterMeters
                                                         where measure.MeterNumber == strMeterNumber
                                                         select measure;
    
                        foreach (WaterMeter meter in waterMeters)
                        {
                            txtMeterDetails.Text = meter.Make + " " +
                                                   meter.Model +
                                                   " (Meter Size: " + meter.MeterSize + ")";
                        }
                    }
                }
            }
        }
    }
  9. Return to the form and double-click the Delete Water Bill button
  10. Return to the form and double-click the Close button
  11. Change the document as follows:
    using System.Data;
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.WaterBills
    {
        public partial class Delete : Form
        {
            public Delete()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterBill_Click(object sender, EventArgs e)
            {
                string strWaterBills = string.Empty;
                List<WaterBill> bills = new List<WaterBill>();
                string fileWaterBills = @"C:\Stellar Water Point2\WaterBills.json";
    
                FileInfo fiWaterBills = new FileInfo(fileWaterBills);
    
                string strAccountsTypes = string.Empty;
                List<AccountType> accountsTypes = new List<AccountType>();
                string fileAccountsTypes = @"C:\Stellar Water Point2\AccountsTypes.json";
    
                FileInfo fiAccountsTypes = new FileInfo(fileAccountsTypes);
    
                if (fiWaterBills.Exists == true)
                {
                    using (TextReader trWaterBills = new StreamReader(fiWaterBills.FullName))
                    {
                        strWaterBills = File.ReadAllText(fiWaterBills.FullName);
                        bills = JsonSerializer.Deserialize<List<WaterBill>>(strWaterBills)!;
    
                        IEnumerable<WaterBill> selected = bills.Where(wb => wb.BillNumber == int.Parse(txtWaterBillNumber.Text));
    
                        foreach (var bill in selected)
                        {
                            txtWaterBillId.Text = bill.WaterBillId.ToString();
                            txtAccountNumber.Text = bill.AccountNumber;
                            txtMeterReadingStartDate.Text = bill.MeterReadingStartDate.ToLongDateString();
                            txtMeterReadingEndDate.Text = bill.MeterReadingEndDate.ToLongDateString();
                            txtBillingDays.Text = bill.BillingDays.ToString();
                            txtCounterReadingStart.Text = bill.CounterReadingStart.ToString();
                            txtCounterReadingEnd.Text = bill.CounterReadingEnd.ToString();
                            txtTotalHCF.Text = bill.TotalHCF.ToString();
                            txtTotalGallons.Text = bill.TotalGallons.ToString();
                            txtFirstTierConsumption.Text = bill.FirstTierConsumption.ToString();
                            txtSecondTierConsumption.Text = bill.SecondTierConsumption.ToString();
                            txtLastTierConsumption.Text = bill.LastTierConsumption.ToString();
                            txtWaterCharges.Text = bill.WaterCharges.ToString();
                            txtSewerCharges.Text = bill.SewerCharges.ToString();
                            txtEnvironmentCharges.Text = bill.EnvironmentCharges.ToString();
                            txtServiceCharges.Text = bill.ServiceCharges.ToString();
                            txtTotalCharges.Text = bill.TotalCharges.ToString();
                            txtLocalTaxes.Text = bill.LocalTaxes.ToString();
                            txtStateTaxes.Text = bill.StateTaxes.ToString();
                            txtPaymentDueDate.Text = bill.PaymentDueDate.ToLongDateString();
                            txtAmountDue.Text = bill.AmountDue.ToString();
                            txtLatePaymentDueDate.Text = bill.LatePaymentDueDate.ToLongDateString();
                            txtLateAmountDue.Text = bill.LateAmountDue.ToString();
                        }
                    }
                }
    
                string strCustomers = string.Empty;
                List<Customer> clients = new List<Customer>();
                string fileCustomers = @"C:\Stellar Water Point2\Customers.json";
    
                FileInfo fiCustomers = new FileInfo(fileCustomers);
    
                string? strMeterNumber = string.Empty;
    
                string strAccountType = string.Empty;
    
                if (fiCustomers.Exists == true)
                {
                    using (TextReader trCustomers = new StreamReader(fiCustomers.FullName))
                    {
                        strCustomers = File.ReadAllText(fiCustomers.FullName);
                        clients = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
    
                        IEnumerable<Customer> customers = from consumer
                                                          in clients
                                                          where consumer.AccountNumber == txtAccountNumber.Text
                                                          select consumer;
    
                        foreach (Customer client in customers)
                        {
                            txtAccountName.Text = client.AccountName;
                            strMeterNumber = client.MeterNumber;
    
                            TextReader trAccountsTypess = new StreamReader(fiAccountsTypes.FullName);
                            strAccountsTypes = File.ReadAllText(fiAccountsTypes.FullName);
                            accountsTypes = JsonSerializer.Deserialize<List<AccountType>>(strAccountsTypes)!;
    
                            foreach (AccountType at in accountsTypes)
                            {
                                if (client.AccountType == at.TypeCode)
                                {
                                    txtAccountType.Text = string.Concat(at.TypeCode, " - ", at.TypeDecription);
                                }
                            }
    
                            txtAddress.Text = client.Address;
                            txtCity.Text = client.City;
                            txtCounty.Text = client.County;
                            txtState.Text = client.State;
                            txtZIPCode.Text = client.ZIPCode;
                        }
                    }
                }
    
                if (strMeterNumber!.Length > 0)
                {
                    string strWaterMeters = string.Empty;
                    List<WaterMeter> waterMeters = new List<WaterMeter>();
                    string fileWaterMeters = @"C:\Stellar Water Point2\WaterMeters.json";
    
                    FileInfo fiWaterMeters = new FileInfo(fileWaterMeters);
    
                    if (fiWaterMeters.Exists == true)
                    {
                        strWaterMeters = File.ReadAllText(fiWaterMeters.FullName);
                        waterMeters = JsonSerializer.Deserialize<List<WaterMeter>>(strWaterMeters)!;
    
                        IEnumerable<WaterMeter> meters = from measure
                                                         in waterMeters
                                                         where measure.MeterNumber == strMeterNumber
                                                         select measure;
    
                        foreach (WaterMeter meter in waterMeters)
                        {
                            txtMeterDetails.Text = meter.Make + " " +
                                                   meter.Model +
                                                   " (Meter Size: " + meter.MeterSize + ")";
                        }
                    }
                }
            }
    
            private void btnDeleteWaterBill_Click(object sender, EventArgs e)
            {
                if (string.IsNullOrEmpty(txtWaterBillNumber.Text))
                {
                    MsgBox.Show("Please provide the bill number of the water bill you want to delete, " +
                                "and then click the Find Water Bill button.");
                    return;
                }
    
                string strWaterBills = string.Empty;
                List<WaterBill> waterBills = new List<WaterBill>();
                string fileWaterBills = @"C:\Stellar Water Point2\WaterBills.json";
    
                FileInfo fiWaterBills = new FileInfo(fileWaterBills);
    
                if (fiWaterBills.Exists == true)
                {
                    strWaterBills = File.ReadAllText(fiWaterBills.FullName);
                    waterBills = JsonSerializer.Deserialize<List<WaterBill>>(strWaterBills)!;
    
                    WaterBill bill = waterBills.Find(bl => bl.BillNumber == int.Parse(txtWaterBillNumber.Text))!;
    
                    if (bill is not null)
                    {
                        if (MsgBox.Question("Are you sure you want to delete (or remove) or cancel " +
                                            "this water bill from the system (you cannot undo the action)?") == Answer.Yes)
                        {
                            waterBills.Remove(bill);
    
                            JsonSerializerOptions options = new JsonSerializerOptions();
                            options.WriteIndented = true;
    
                            string jsWaterBills = JsonSerializer.Serialize(waterBills, typeof(List<WaterBill>), options);
                            File.WriteAllText(fiWaterBills.FullName, jsWaterBills);
    
                            MsgBox.Show("The water bill has been deleted (or removed, or cancelled) from our system.");
                        }
                    }
                }
    
                Close();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  12. In the Solution Explorer, below the WaterBills folder, double-click Central.cs to open its form
  13. From the Toolbox, add two buttons to the form below the list view and to the right of the Edit Water Bill button
  14. 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 btnProcessWaterBill &Process 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
  15. On the form, double-click the Delete Water Bill button
  16. Return to the Water Bills - Central form and double-click the Close button
  17. Implement the events as follows:
    using System.Text.Json;
    using StellarWaterPoint2.Models;
    
    namespace StellarWaterPoint2.WaterBills
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowWaterBills()
            {
                // We will need the list of customers to display an account summary in the list view
                // Declare a strCustomers variable that will hold the records from the JSON file
                string strCustomers = string.Empty;
                // Prepare a list to hold the records of customers
                List<Customer> clients = new List<Customer>();
                // Specify the file that holds the records of customers
                string fileCustomers = @"C:\Stellar Water Point2\Customers.json";
    
                // Create a FileInfo object for the records of customers
                FileInfo fiCustomers = new FileInfo(fileCustomers);
    
                // Check if a file that holds the records of customers was created already
                if (fiCustomers.Exists == true)
                {
                    // If that file exists, create a TextReader object to get those records
                    using (TextReader trCustomers = new StreamReader(fiCustomers.FullName))
                    {
                        // Read the records and store them in the strCustomers variable
                        strCustomers = File.ReadAllText(fiCustomers.FullName);
                        // Use JSON deserialization to get the records of customers
                        clients = JsonSerializer.Deserialize<List<Customer>>(strCustomers)!;
                    }
                }
    
                // Declare a strWaterBills variable that will hold the records from the JSON file
                string strWaterBills = string.Empty;
                // Prepare a bills list to hold the records of water bills
                List<WaterBill> bills = new List<WaterBill>();
                // Specify the file that holds the records of water bills
                string fileWaterBills = @"C:\Stellar Water Point2\WaterBills.json";
    
                // Create a FileInfo object for the records of water bills
                FileInfo fiWaterBills = new FileInfo(fileWaterBills);
    
                // Find out whether a file that holds the records of water bills exists already
                if (fiWaterBills.Exists == true)
                {
                    // If that file exists, create a TextReader object to read the file
                    using (TextReader trWaterBills = new StreamReader(fiWaterBills.FullName))
                    {
                        /* Read the contents of the file that holds the water bills.
                         * Store the read text in the strWaterBills variable that was declared. */
                        strWaterBills = File.ReadAllText(fiWaterBills.FullName);
                        // Get the water bills and store them in the bills list variable
                        bills = JsonSerializer.Deserialize<List<WaterBill>>(strWaterBills)!;
    
                        /* We are about to display the water bills records in the list view.
                         * Before proceeding, first remove any record in the list view. */
                        lvwWaterBills.Items.Clear();
    
                        // Visit each record of the water bills
                        foreach (WaterBill invoice in bills)
                        {
                            /* Prepare a ListViewItem object for each record.
                             * Display the record counter in the first column of this object. */
                            ListViewItem lviWaterBill = new ListViewItem(invoice.WaterBillId.ToString());
    
                            // Display the water bill number of the current record
                            lviWaterBill.SubItems.Add(invoice.BillNumber.ToString());
    
                            /* Refer to the list of records of the customers (that list was prepared earlier).
                             * Use LINQ to get the customer whose account number is 
                             * the same as the account number of the current record. */
                            IEnumerable<Customer> customer = clients.Where(cust => cust.AccountNumber == invoice.AccountNumber);
    
                            // Now that we have located the customer record, display some details about it
                            foreach (Customer cust in customer)
                            {
                                lviWaterBill.SubItems.Add(invoice.AccountNumber + " - " +
                                                          cust.AccountName +
                                                          ", Type: " + cust.AccountType![..3] +
                                                          ", (Mtr #: " + cust.MeterNumber + ")");
                            }
    
                            /* Continue displaying some other parts of the water bill.
                             * Before there is not enough space for the whole water bill, we display only some values. */
                            lviWaterBill.SubItems.Add(invoice.MeterReadingStartDate.ToShortDateString());
                            lviWaterBill.SubItems.Add(invoice.MeterReadingEndDate.ToShortDateString());
                            lviWaterBill.SubItems.Add(invoice.BillingDays.ToString());
                            lviWaterBill.SubItems.Add(invoice.CounterReadingStart.ToString());
                            lviWaterBill.SubItems.Add(invoice.CounterReadingEnd.ToString());
                            lviWaterBill.SubItems.Add(invoice.TotalHCF.ToString());
                            lviWaterBill.SubItems.Add(invoice.TotalGallons.ToString());
                            lviWaterBill.SubItems.Add(invoice.PaymentDueDate.ToShortDateString());
                            lviWaterBill.SubItems.Add(invoice.AmountDue.ToString());
    
                            lvwWaterBills.Items.Add(lviWaterBill);
                        }
                    }
                }
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                ShowWaterBills();
            }
    
            private void btnProcessWaterBill_Click(object sender, EventArgs e)
            {
                Create create = new Create();
                
                create.ShowDialog();
    
                ShowWaterBills();
            }
    
            private void btnWaterBillDetails_Click(object sender, EventArgs e)
            {
                Details details = new Details();
                
                details.ShowDialog();
            }
    
            private void btnWaterBillEditor_Click(object sender, EventArgs e)
            {
                Editor update = new Editor();
    
                update.ShowDialog();
                
                ShowWaterBills();
            }
    
            private void btnDeleteWaterBill_Click(object sender, EventArgs e)
            {
                Delete delete = new Delete();
                
                delete.ShowDialog();
                
                ShowWaterBills();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  18. To execute, on the main menu, click Debug -> Start Without Debugging:

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

    Stellar Water Point - Water Bills

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

    Stellar Water Point - Water Bill Deletion

  21. In the Water Bill # text box, type 917829:

    Stellar Water Point - Water Bill Deletion

  22. Click Find Water Bill

    Stellar Water Point - Water Bill Deletion

  23. Click Delete Water Bill:

    Stellar Water Point - Water Bill Deletion

  24. Read the message in the message box and click Yes:

    Stellar Water Point - Water Bill Deletion

  25. Read the message in the message box and click OK:

    Stellar Water Point - Water Bills

  26. Close the forms and return to your programming environment
  27. Close Microsoft Visual Studio

Home Copyright © 2010-2026, FunctionX Sunday 11 June 2023 Home