Project Start Up

Introduction

This exercise is to create a graphical application for a (fictitious) water company. The application will be created as Windows Forms (WinForms). Probably the most important part, as far as programming is concerned, is the use of the Entity Framework.

Practical LearningPractical Learning: Introducing the Application

  1. Start Microsoft Visual Studio
  2. In the Visual Studio 2022 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 StellarWaterPoint5
  7. In the Additional Information wizard page, in the Framework combo box, select the highest version (.NET 9.0 (Standard Term Support)).
    Click Create
  8. In the Solution Explorer, right-click the name of the project -> Add -> Folder
  9. Type Models as the name of the folder and press Enter
  10. In the Solution Explorer, right-click Models -> Add -> Class...
  11. Type MsgBox as the Name of the file
  12. Press Enter
  13. Change the class as follows:
    namespace StellarWaterPoint52.Models
    {
        public class MsgBox
        {
            public static void Regular(string message)
            {
                MessageBox.Show(message,
                                "Stellar Water Point",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Information);
            }
            
            public static DialogResult Question(string message)
            {
                DialogResult result = MessageBox.Show(message,
                                      "Stellar Water Point",
                                      MessageBoxButtons.YesNoCancel,
                                      MessageBoxIcon.Question);
    
                switch (result)
                {
                    case DialogResult.Yes:
                        return DialogResult.Yes;
                    case DialogResult.No:
                        return DialogResult.No;
                    case DialogResult.Cancel:
                        return DialogResult.Cancel;
                    default:
                        return DialogResult.OK;
                }
            }
        }
    }

Introducing the Entity Framework

To create and manage the records of our application, we will use the Entity Framework. If you are working on a Windows Forms application, you must install that framework as a NuGet package.

Practical LearningPractical Learning: Installing the Entity Framework

  1. To install the Entity Framework, in the Solution Explorer, right-click the name of the project and click Manage NuGet Packages...
  2. In the NuGet tab, click Browse
  3. Click the combo box and type entityframework
  4. In the list, click EntityFramework
  5. Click Install
  6. In the Preview Pages dialog box, click Apply
  7. In the License Acceptance dialog box, click I Accept
  8. In the Solution Explorer, right-click Models -> Add -> Class...
  9. Set the file Name to StellarContext
  10. Click Add
  11. Indicate that the class is derivec from DbContext:
    using System.Data.Entity;
    
    namespace StellarWaterPoint51.Models
    {
        public class StellarContext : DbContext
        {
        }
    }

The Main Form of the Application

When you create a Windows Forms application in Microsoft Visual Studio, the studio automatically creates a default or starting form. We will configure that form to be the central object of the application.

Practical LearningPractical Learning: Preparing the Main Form of the Application

  1. In the Solution Explorer, right-click Form1.cs and click Rename
  2. Type StellarManagement (to get StellarManagement.cs) and press Enter
  3. Read the message on the message box and click Yes
  4. In the Solution Explorer, double-click StellarManagement.cs to display the form
  5. 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

Water Meters

Introduction

The business for the type of application we are creating must use water meters to measure the amount of water that is consumed. We will create forms that can be used to manage water meters.

Practical LearningPractical Learning: Displaying Water Meters

  1. To create a class, in the Solution Explorer, right-click Models -> Add -> Class...
  2. Replace the name with WaterMeter
  3. Click Add
  4. Change the code as follows:
    using System.ComponentModel.DataAnnotations;
    
    namespace StellarWaterPoint51.Models
    {
        public class WaterMeter
        {
            [Key]
            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; }
        }
    }
  5. Click the StellarContext.cs tab
  6. Change the class as follows:
    using System.Data.Entity;
    
    namespace StellarWaterPoint51.Models
    {
        public class StellarContext : DbContext
        {
            public DbSet<WaterMeter>? WaterMeters { get; set; }
        }
    }
  7. In the Solution Explorer, right-click StellarWaterPoint5 -> Add -> New Folder
  8. Type WaterMeters as the name of the folder

Displaying Water Meters

Eventually, when the records of water meters will have been created, if the user wants to see a list of water meters, we will create a form for that purpose.

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 Id 40  
    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 StellarWaterPoint51.Models;
    
    namespace StellarWaterPoint51.WaterMeters
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowWaterMeters()
            {
                StellarContext db = new();
                List<WaterMeter> meters = new();
    
                meters = db.WaterMeters!.ToList();
    
                lvwWaterMeters.Items.Clear();
    
                foreach (WaterMeter meter in meters)
                {
                    ListViewItem lviWaterMeter = new ListViewItem(meter.WaterMeterId.ToString());
    
                    lviWaterMeter.SubItems.Add(meter.MeterNumber);
                    lviWaterMeter.SubItems.Add(meter.Make);
                    lviWaterMeter.SubItems.Add(meter.Model);
                    lviWaterMeter.SubItems.Add(meter.MeterSize);
                    lvwWaterMeters.Items.Add(lviWaterMeter);
                }
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                ShowWaterMeters();
            }
        }
    }
  11. In the Solution Explorer, double-click StellarManagement.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 FlatStyle
    Button Button btnWaterMeters &Water Meters... Times New Roman, 24pt, style=Bold Flat
  14. Double-click the &Water Meters button
  15. Impliment the event as follows:
    namespace StellarWaterPoint2
    {
        public partial class StellarManagement : Form
        {
            public StellarManagement()
            {
                InitializeComponent();
            }
    
            private void btnWaterMeters_Click(object sender, EventArgs e)
            {
                WaterMeters.Central central = new WaterMeters.Central();
    
                central.Show();
            }
        }
    }

A Water Meter Record

For the type of business whose application we are creating, every water meter must be represented with a record. We will have a form that can be used to create a record for each 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
    Label Label   M&ake:  
    TextBox Text Box txtMake  
    Label Label   M&odel:  
    TextBox Text Box txtModel  
    Label Label   Me&ter Size:  
    TextBox Text Box txtMeterSize  
    Button Button btnSaveWaterMeter &Save Water Meter FlatStyle: Flat
    Button Button btnClose &Close FlatStyle: Flat
  4. Using the Properties window, change some characteristics of the form as follows:
    FormBorderStyle: FixedDialog
    Text:            Stellar Water Point - Water Meter Setup
    StartPosition:   CenterScreen
    ShowInTaskbar:   False
  5. On the form, double-click the Save Water Meter button
  6. Implement the event as follows:
    using StellarWaterPoint51.Models;
    
    namespace StellarWaterPoint51.WaterMeters
    {
        public partial class Create : Form
        {
            public Create()
            {
                InitializeComponent();
            }
    
            private void btnSaveWaterMeter_Click(object sender, EventArgs e)
            {
                string strMeterNumber = mtbMeterNumber.Text.Replace("-", "").Trim();
    
                if (string.IsNullOrEmpty(strMeterNumber))
                {
                    MsgBox.Regular("You must type a meter number. " +
                                   "Otherwise, the water meter cannot be set up.");
                    return;
                }
    
                StellarContext db = new();
    
                WaterMeter meter = new WaterMeter()
                {
                    MeterNumber = mtbMeterNumber.Text,
                    Make        = txtMake.Text,
                    Model       = txtModel.Text,
                    MeterSize   = txtMeterSize.Text
                };
    
                db.WaterMeters!.Add(meter);
                db.SaveChanges();
    
                Close();
            }
        }
    }
  7. Return to the form and double-click the Close button
  8. Implement the event as follows:
    using StellarWaterPoint51.Models;
    
    namespace StellarWaterPoint51.WaterMeters
    {
        public partial class Create : Form
        {
            public Create()
            {
                InitializeComponent();
            }
    
            private void btnSaveWaterMeter_Click(object sender, EventArgs e)
            {
                /* We want to check that the user had provided a water meter number.
                 * Since we are using a masked text box, and since its internal symbols 
                 * are counted as being part of the whole value, we need to remove those 
                 * symbols. We will also "trim" the value to remove the empty spaces. */
                string strMeterNumber = mtbMeterNumber.Text.Replace("-", "").Trim();
    
                /* Make sure the user provides a meter number
                 * as the minimum piece of information for a water meter. */
                if (string.IsNullOrEmpty(strMeterNumber))
                {
                    MsgBox.Regular("You must type a meter number. " +
                                   "Otherwise, the water meter cannot be set up.");
                    return;
                }
    
                // Declare a variable for the Entity Framework database context
                StellarContext db = new();
    
                /* Get the values for a water meter from the New Water Meter form.
                 * Create a WaterMeter object using those values. */
                WaterMeter meter = new WaterMeter()
                {
                    MeterNumber = mtbMeterNumber.Text,
                    Make        = txtMake.Text,
                    Model       = txtModel.Text,
                    MeterSize   = txtMeterSize.Text
                };
    
                // Add the created WaterMeter object to the collection of records in the application
                db.WaterMeters!.Add(meter);
                // Save the record to the database
                db.SaveChanges();
    
                Close();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  9. In the Solution Explorer, below the WaterMeters folder, double-click Central.cs
  10. From the Toolbox, add a button to the form below the list view
  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 btnNewWaterMeter Text: &New Water Meter...
    FlatStyle: Flat
  12. Double-click the New Water Meter
  13. Implement the event class as follows:
    using StellarWaterPoint51.Models;
    
    namespace StellarWaterPoint51.WaterMeters
    {
        public partial class Central : Form
        {
            StellarContext db = new();
    
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowWaterMeters()
            {
                List<WaterMeter> meters = new();
    
                meters = db.WaterMeters!.ToList();
    
                lvwWaterMeters.Items.Clear();
    
                foreach (WaterMeter meter in meters)
                {
                    ListViewItem lviWaterMeter = new ListViewItem(meter.WaterMeterId.ToString());
    
                    lviWaterMeter.SubItems.Add(meter.MeterNumber);
                    lviWaterMeter.SubItems.Add(meter.Make);
                    lviWaterMeter.SubItems.Add(meter.Model);
                    lviWaterMeter.SubItems.Add(meter.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();
    
                create.ShowDialog();
    
                ShowWaterMeters();
            }
        }
    }
  14. To execute the application, on the main menu, click Debug -> Start Without Debugging

    Stellar Water Point

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

    Stellar Water Point - Water Meters

  16. Click the New Water Meter button:

    Stellar Water Point - New Water Meter

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

  18. Close the forms and return to your programming environment
  19. In the Solution Explorer, double-click StellarManagement.cs to display the main form of the application
  20. Right-click the form and click View Code
  21. Change the StellarManagement() constructor as follows:
    using StellarWaterPoint51.Models;
    
    namespace StellarWaterPoint51
    {
        public partial class StellarManagement : Form
        {
            public StellarManagement()
            {
                InitializeComponent();
    
                StellarContext db = new();
                WaterMeter? meter = null;
    
                /*  */
                
            }
    
            private void btnWaterMeters_Click(object sender, EventArgs e)
            {
                WaterMeters.Central central = new WaterMeters.Central();
                
                central.Show();
            }
        }
    }
  22. To execute the application, on the main menu, click Debug -> Start Without Debugging
  23. Close the form and return to your programming environment
  24. Change the StellarManagement() constructor as follows:
    using StellarWaterPoint51.Models;
    
    namespace StellarWaterPoint51
    {
        public partial class StellarManagement : Form
        {
            public StellarManagement()
            {
                InitializeComponent();
    
                /* StellarContext db = new();
                WaterMeter? meter = null;
    
                */
            }
    
            private void btnWaterMeters_Click(object sender, EventArgs e)
            {
                WaterMeters.Central central = new WaterMeters.Central();
                
                central.Show();
            }
        }
    }

Water Meter Details

To let the user view the details of a water meter, we will create a simple 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     FlatStyle: Flat 
    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  
    Button Button btnClose &Close     FlatStyle: Flat
  5. On the form, double-click the Find Water Meter button
  6. Implement the event as follows:
    using StellarWaterPoint5.Models;
    
    namespace StellarWaterPoint51.WaterMeters
    {
        public partial class Details : Form
        {
            public Details()
            {
                InitializeComponent();
            }
    
            private void btnFindWateMeter_Click(object sender, EventArgs e)
            {
                try
                {
                    string strMeterNumber = mtbMeterNumber.Text.Replace("-", "").Trim();
    
                    if (string.IsNullOrEmpty(strMeterNumber))
                    {
                        MsgBox.Regular("You should first type a valid meter number, " +
                                       "and then click the Find Water Meter button.");
                        return;
                    }
    
                    StellarContext db = new();
                    List<WaterMeter> meters = new();
    
                    meters = db.WaterMeters!.ToList();
                    WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == mtbMeterNumber.Text);
    
                    txtMake.Text = meter!.Make;
                    txtModel.Text = meter.Model;
                    txtMeterSize.Text = meter.MeterSize;
                    }
                    catch (NullReferenceException nre)
                    {
                        MsgBox.Regular("The number you typed doesn't match " +
                                       "any of the water meters in our system." + Environment.NewLine +
                                       "The error produced was: " + nre.Message);
                    }
                }
            }
        }
    }
  7. Return to the form and double-click the Close button
  8. Implement the event as follows:
    using StellarWaterPoint51.Models;
    
    namespace StellarWaterPoint51.WaterMeters
    {
        public partial class Details : Form
        {
            public Details()
            {
                InitializeComponent();
            }
    
            private void btnFindWateMeter_Click(object sender, EventArgs e)
            {
                // Use Exception Handling in case something would go wrong
                try
                {
                    /* We want to check that the user had provided a water meter number.
                                 * Since we are using a masked text box, and since its internal symbols 
                                 * are counted as being part of the whole value, we need to remove those 
                                 * symbols. We will also "trim" the value to remove the empty spaces. */
                    string strMeterNumber = mtbMeterNumber.Text.Replace("-", "").Trim();
    
                    // Make sure the user typed a (valid) water meter number.
                    if (string.IsNullOrEmpty(strMeterNumber))
                    {
                        MsgBox.Regular("You should first type a valid meter number, " +
                                    "and then click the Find Water Meter button.");
    
                        // If the user didn't type a water meter number, don't do nothing.
                        return;
                    }
    
                    // Get a reference to the EF context class
                    StellarContext db = new();
                    // Get a list that can contain the records of water meters
                    List<WaterMeter> meters = new();
    
                    // If some records of water meters exist, access them and store them in the List<> variable
                    meters = db.WaterMeters!.ToList();
                    /* If a list of water meters exists, find in it the water meter that has 
                     * the same meter number as the value the user had typed in the masked text box. */
                    WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == mtbMeterNumber.Text);
    
                    // If the water meter was found, put its values in the text boxes
                    txtMake.Text = meter!.Make;
                    txtModel.Text = meter.Model;
                    txtMeterSize.Text = meter.MeterSize;
                }
                catch (NullReferenceException nre)
                {
                    /* If the user typed some digits inthe water meter masked text box, find out whether 
                     * that number corresponds to a valid water meter. If the number the user typed doesn't match 
                     * any water meter number, then the application produced a NullReferenceException exception. */
                    MsgBox.Regular("The number you typed doesn't match " +
                                   "any of the water meters in our system." + Environment.NewLine +
                                   "The error produced was: " + nre.Message);
                }
            }
    
            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...
    FlatStyle: Flat
  12. Double-click the View Water Meter button
  13. Change the document as follows:
    using StellarWaterPoint51.Models;
    
    namespace StellarWaterPoint51.WaterMeters
    {
        public partial class Central : Form
        {
            StellarContext db = new();
    
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowWaterMeters()
            {
                List<WaterMeter> meters = new();
    
                meters = db.WaterMeters!.ToList();
    
                lvwWaterMeters.Items.Clear();
    
                foreach (WaterMeter meter in meters)
                {
                    ListViewItem lviWaterMeter = new ListViewItem(meter.WaterMeterId.ToString());
    
                    lviWaterMeter.SubItems.Add(meter.MeterNumber);
                    lviWaterMeter.SubItems.Add(meter.Make);
                    lviWaterMeter.SubItems.Add(meter.Model);
                    lviWaterMeter.SubItems.Add(meter.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();
    
                create.ShowDialog();
    
                ShowWaterMeters();
            }
    
            private void btnDetailsWaterMeter_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 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 Details form
  20. On the Water Meters form, double-click the third record
  21. Close the forms and return to your programming environment

Updating a Water Meter

If or when some detail about a water meter changes, we will create a form that can let a user update any piece of information about 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   FlatStyle: Flat
    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 btnFindWateMeter &Find Wate Meter   FlatStyle: Flat
    Button Button btnClose &Close   FlatStyle: Flat 
  5. On the form, double-click the Find Water Meter button
  6. Change the document as follows:
    using StellarWaterPoint51.Models;
    
    namespace StellarWaterPoint51.WaterMeters
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void btnFindWateMeter_Click(object sender, EventArgs e)
            {
                try {
                    string strMeterNumber = mtbMeterNumber.Text.Replace("-", "").Trim();
    
                    if (string.IsNullOrEmpty(strMeterNumber))
                    {
                        MsgBox.Regular("You should first type a valid meter number, " +
                                       "and then click the Find Water Meter button.");
                        return;
                    }
    
                    StellarContext db = new();
                    List<WaterMeter> meters = new();
    
                    meters = db.WaterMeters!.ToList();
                    WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == mtbMeterNumber.Text);
    
                    txtMake.Text = meter!.Make;
                    txtModel.Text = meter.Model;
                    txtMeterSize.Text = meter.MeterSize;
                }
                catch (NullReferenceException nre)
                {
                    MsgBox.Regular("The number you typed doesn't match " +
                                   "any of the water meters in our system." + Environment.NewLine +
                                   "The error produced was: " + nre.Message);
                }
            }    
        }
    }
  7. Return to the form and double-click the Update Water Meter button
  8. Implement the event as follows:
    using StellarWaterPoint51.Models;
    
    namespace StellarWaterPoint51.WaterMeters
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void btnFindWateMeter_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void btnUpdateWaterMeter_Click(object sender, EventArgs e)
            {
                string strMeterNumber = mtbMeterNumber.Text.Replace("-", "").Trim();
    
                if (string.IsNullOrEmpty(strMeterNumber))
                {
                    MsgBox.Regular("You must type a meter number. " +
                                   "Otherwise, the water meter cannot be set up.");
                    return;
                }
    
                StellarContext db = new();
    
                List<WaterMeter> meters = new();
    
                meters = db.WaterMeters!.ToList();
                WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == mtbMeterNumber.Text);
    
                if (meter is null)
                {
                    MsgBox.Regular("There is no water meter with that number in our system.");
                    return;
                }
                
                meter!.Make = txtMake.Text;
                meter.Model = txtModel.Text;
                meter.MeterSize = txtMeterSize.Text;
    
                db.SaveChanges();
    
                Close();
            }
        }
    }
  9. Return to the form and double-click the Close button
  10. Change the document as follows:
    using StellarWaterPoint51.Models;
    
    namespace StellarWaterPoint51.WaterMeters
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void btnFindWateMeter_Click(object sender, EventArgs e)
            {
                try {
                    /* We want to check that the user had provided a water meter number.
                     * Since we are using a masked text box, and since its internal symbols 
                     * are counted as being part of the whole value, we need to remove those 
                     * symbols. We will also "trim" the value to remove the empty spaces. */
                    string strMeterNumber = mtbMeterNumber.Text.Replace("-", "").Trim();
    
                    // Make sure the user typed a (valid) water meter number.
                    if (string.IsNullOrEmpty(strMeterNumber))
                    {
                        MsgBox.Regular("You should first type a valid meter number, " +
                                       "and then click the Find Water Meter button.");
    
                        // If the user didn't type a water meter number, don't do nothing.
                        return;
                    }
    
                    // Get a reference to the EF context class
                    StellarContext db = new();
                    // Get a list that can contain the records of water meters
                    List<WaterMeter> meters = new();
    
                    // If some records of water meters exist, access them and store them in the List<> variable
                    meters = db.WaterMeters!.ToList();
                    /* If a list of water meters exists, find in it the water meter that has 
                     * the same meter number as the value the user had typed in the masked text box. */
                    WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == mtbMeterNumber.Text);
    
                    // If the water meter was found, put its values in the text boxes
                    txtMake.Text = meter!.Make;
                    txtModel.Text = meter.Model;
                    txtMeterSize.Text = meter.MeterSize;
                }
                catch (NullReferenceException nre)
                {
                    MsgBox.Regular("The number you typed doesn't match " +
                                   "any of the water meters in our system." + Environment.NewLine +
                                   "The error produced was: " + nre.Message);
                }
            }
    
            private void btnUpdateWaterMeter_Click(object sender, EventArgs e)
            {
                /* We want to check that the user had provided a water meter number.
                 * Since we are using a masked text box, and since its internal symbols 
                 * are counted as being part of the whole value, we need to remove those 
                 * symbols. We will also "trim" the value to remove the empty spaces. */
                string strMeterNumber = mtbMeterNumber.Text.Replace("-", "").Trim();
    
                /* Make sure the user provides a meter number
                 * as the minimum piece of information for a water meter. */
                if (string.IsNullOrEmpty(strMeterNumber))
                {
                    MsgBox.Regular("You must type a meter number. " +
                                   "Otherwise, the water meter cannot be set up.");
                    return;
                }
    
                // Declare a variable for the Entity Framework database context
                StellarContext db = new();
    
                // Get a list that can contain the records of water meters
                List<WaterMeter> meters = new();
    
                // If some records of water meters exist, access them and store them in the List<> variable
                meters = db.WaterMeters!.ToList();
                /* If a list of water meters exists, find in it the water meter that has 
                 * the same meter number as the value the user had typed in the masked text box. */
                WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == mtbMeterNumber.Text);
    
                if (meter is null)
                {
                    MsgBox.Regular("There is no water meter with that number in our system.");
                    return;
                }
                
                meter!.Make = txtMake.Text;
                meter.Model = txtModel.Text;
                meter.MeterSize = txtMeterSize.Text;
    
                // Save the record to the database
                db.SaveChanges();
    
                Close();
            }
    
            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...
    Anchor: Bottom, Right
    FlatStyle: Flat
  14. Display the Central form of the WaterMeters folder
  15. Double-click the Update Water Meter 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()
            {
                . . .
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                ShowWaterMeters();
            }
    
            private void btnNewWaterMeter_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void btnViewWaterMeter_Click(object sender, EventArgs e)
            {
                Details view = new();
    
                view.ShowDialog();
    
                ShowWaterMeters();
            }
    
            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
  18. On the Central form, click the Water Meters button
  19. Click the Edit 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 - New Water Meter

  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

When a user decides to delete the record of a water meter, we will provide 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 - 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   FlatStyle: Flat 
    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 btnDeleteWaterMeter &Delete Water Meter   FlatStyle: Flat 
    Button Button btnClose &Close   FlatStyle: Flat 
  5. On the form, double-click the Find Water Meter button
  6. Change the document as tollows:
    using StellarWaterPoint51.Models;
    
    namespace StellarWaterPoint51.WaterMeters
    {
        public partial class Delete : Form
        {
            public Delete()
            {
                InitializeComponent();
            }
    
            private void btnFindWateMeter_Click(object sender, EventArgs e)
            {
                try {
                    string strMeterNumber = mtbMeterNumber.Text.Replace("-", "").Trim();
    
                    if (string.IsNullOrEmpty(strMeterNumber))
                    {
                        MsgBox.Regular("You should first type a valid meter number, " +
                                       "and then click the Find Water Meter button.");
                        return;
                    }
    
                    StellarContext db = new();
                    List<WaterMeter> meters = new();
    
                    meters = db.WaterMeters!.ToList();
                    WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == mtbMeterNumber.Text);
    
                    txtMake.Text = meter!.Make;
                    txtModel.Text = meter.Model;
                    txtMeterSize.Text = meter.MeterSize;
                }
                catch (NullReferenceException nre)
                {
                    MsgBox.Regular("The number you typed doesn't match " +
                                   "any of the water meters in our system." + Environment.NewLine +
                                   "The error produced was: " + nre.Message);
                }
            }
        }
    }
  7. Return to the form and double-click the Delete Water Meter button
  8. Implement the event as tollows:
    using StellarWaterPoint51.Models;
    
    namespace StellarWaterPoint51.WaterMeters
    {
        public partial class Delete : Form
        {
            public Delete()
            {
                InitializeComponent();
            }
    
            private void btnFindWateMeter_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void btnDeleteWaterMeter_Click(object sender, EventArgs e)
            {
                try {
                    string strMeterNumber = mtbMeterNumber.Text.Replace("-", "").Trim();
    
                    if (string.IsNullOrEmpty(strMeterNumber))
                    {
                        MsgBox.Regular("You must type a meter number. " +
                                       "Otherwise, the water meter cannot be set up.");
                        return;
                    }
    
                    StellarContext db       = new();
                    List<WaterMeter> meters = new();
    
                    meters                  = db.WaterMeters!.ToList();
                    WaterMeter? meter       = meters.Find(mtr => mtr.MeterNumber == mtbMeterNumber.Text);
    
                    // Check if the user had provided a valid meter number for an existing water meter
                    if (meter is null)
                    {
                        MsgBox.Regular("You must provide a valid water meter number that exists in our system.");
                        return;
                    }
    
                    /* If the user had put a valid water meter, ask the user if 
                     * he/she really wants to delete the water meter record. */
                    string strQuestion = "Are you sure you want to delete this " +
                                         "water meter (the operation cannot be undone)?";
    
                    if (MsgBox.Question(strQuestion) == DialogResult.Yes)
                    {
                        // If the user answered Yes to the question, delete the water meter record...
                        db.WaterMeters!.Remove(meter);
                        // then save the table without the deleted record.
                        db.SaveChanges();
                    }
    
                    // Return to the Central form of the Water Meters
                    Close();
                }
                catch (NullReferenceException nre)
                {
                    MsgBox.Regular("The number you typed doesn't match " +
                                   "any of the water meters in our system." + Environment.NewLine +
                                   "The error produced was: " + nre.Message);
                }
    
                Close();
            }
        }
    }
  9. Return to the form and double-click the Close button
  10. Change the document as tollows:
    using StellarWaterPoint51.Models;
    
    namespace StellarWaterPoint51.WaterMeters
    {
        public partial class Delete : Form
        {
            public Delete()
            {
                InitializeComponent();
            }
    
            private void btnFindWateMeter_Click(object sender, EventArgs e)
            {
                /* We want to check that the user had provided a water meter number.
                 * Since we are using a masked text box, and since its internal symbols 
                 * are counted as being part of the whole value, we need to remove those 
                 * symbols. We will also "trim" the value to remove the empty spaces. */
                string strMeterNumber = mtbMeterNumber.Text.Replace("-", "").Trim();
    
                // Make sure the user typed a (valid) water meter number.
                if (string.IsNullOrEmpty(strMeterNumber))
                {
                    MsgBox.Regular("You should first type a valid meter number, " +
                                   "and then click the Find Water Meter button.");
    
                    // If the user didn't type a water meter number, don't do nothing.
                    return;
                }
    
                // Get a reference to the EF context class
                StellarContext db = new();
                // Get a list that can contain the records of water meters
                List<WaterMeter> meters = new();
    
                // If some records of water meters exist, access them and store them in the List<> variable
                meters = db.WaterMeters!.ToList();
                /* If a list of water meters exists, find in it the water meter that has 
                 * the same meter number as the value the user had typed in the masked text box. */
                WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == mtbMeterNumber.Text);
    
                // If the water meter was found, put its values in the text boxes
                txtMake.Text = meter!.Make;
                txtModel.Text = meter.Model;
                txtMeterSize.Text = meter.MeterSize;
            }
    
            private void btnDeleteWaterMeter_Click(object sender, EventArgs e)
            {
                string strMeterNumber = mtbMeterNumber.Text.Replace("-", "").Trim();
    
                if (string.IsNullOrEmpty(strMeterNumber))
                {
                    MsgBox.Regular("If you are planning to delete a water meter record, " +
                                   "first type a valid meter number, " +
                                   "then click the Find Water Meter button, " +
                                   "and the click the Delete Water Meter button.");
    
                    // If the user didn't type a water meter number, don't do anything.
                    return;
                }
    
                StellarContext db = new();
                List<WaterMeter> meters = new();
    
                // Get the list of water meters and store it in a List<WaterMeter> collection named "meters"
                meters = db.WaterMeters!.ToList();
    
                WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == mtbMeterNumber.Text);
                
                // Check if the user had provided a valid meter number for an existing water meter
                if (meter is not null)
                {
                    /* If the user had put a valid water meter, ask the user if 
                     * he/she really wants to delete the water meter record. */
                    string strQuestion = "Are you sure you want to delete this water meter (the operation cannot be undone)?";
                    
                    if (MessageBox.Show(strQuestion, "Stellar Water Point",
                                        MessageBoxButtons.YesNoCancel,
                                        MessageBoxIcon.Question) == DialogResult.Yes)
                    {
                        // If the user answered Yes to the question, delete the water meter record...
                        db.WaterMeters!.Remove(meter);
                        // then save the table without the deleted record.
                        db.SaveChanges();
                    }
                }
    
                // Return to the Central form of the Water Meters
                Close();
            }
    
            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... FlatStyle: Flat
    Bottom, Right
    Button Button btnViewWaterMeter &View Water Meter... FlatStyle: Flat
    Bottom, Right
    Button Button btnEditWaterMeter &Edit Water Meter... FlatStyle: Flat
    Bottom, Right
    Button Button btnDeleteWateMeter &Delete Water Meter... FlatStyle: Flat
    Bottom, Right
    Button Button btnClose &Close FlatStyle: Flat
    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 StellarWaterPoint51.Models;
    
    namespace StellarWaterPoint51.WaterMeters
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowWaterMeters()
            {
                // Get a reference to the database context
                StellarContext db = new();
                // Prepare a collection variable to water meters
                List<WaterMeter> meters = new();
    
                // Get a list of water meters and store in a declared collection variable
                meters = db.WaterMeters!.ToList();
    
                /* Whenever you are plaaning to display some records in the list view, 
                 * first remove everything from that list box as if you are refreshing it. */
                lvwWaterMeters.Items.Clear();
    
                // Visit each water meter record...
                foreach (WaterMeter meter in meters)
                {
                    // ... and create its record as a list view item
                    ListViewItem lviWaterMeter = new ListViewItem(meter.WaterMeterId.ToString());
    
                    lviWaterMeter.SubItems.Add(meter.MeterNumber);
                    lviWaterMeter.SubItems.Add(meter.Make);
                    lviWaterMeter.SubItems.Add(meter.Model);
                    lviWaterMeter.SubItems.Add(meter.MeterSize);
                    // Add the prepared list view to the items of the list view
                    lvwWaterMeters.Items.Add(lviWaterMeter);
                }
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                ShowWaterMeters();
            }
    
            private void btnNewWaterMeter_Click(object sender, EventArgs e)
            {
                Create create = new();
    
                create.ShowDialog();
    
                ShowWaterMeters();
            }
    
            private void btnDetailsWaterMeter_Click(object sender, EventArgs e)
            {
                Details details = new();
    
                details.Show();
            }
    
            private void btnWaterMeterEditor_Click(object sender, EventArgs e)
            {
                Editor editor = new();
    
                editor.ShowDialog();
    
                ShowWaterMeters();
            }
    
            private void btnDeleteWaterMeter_Click(object sender, EventArgs e)
            {
                Delete delete = new();
    
                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 738-588-249
  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:

    Stellar Water Point - Water Meter Deletion

    On the message box, click Yes

    Stellar Water Point - Water Meters

  24. Close the forms and return to your programming environment

Customers

Introduction

Various types of entities use the services of a water distribution company. We will provide forms to help a user manage the records of the water services consumers.

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 Customer
  4. Click Add
  5. Change the code as follows:
    namespace StellarWaterPoint5.Models
    {
        public class Customer
        {
            [Key]
            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; }
        }
    }
  6. In the Solution Explorer, below Models, double-click the StellarContext.cs file
  7. Change the class as follows:
    using System.Data.Entity;
    
    namespace StellarWaterPoint51.Models
    {
        public class StellarContext : DbContext
        {
            public DbSet<WaterMeter>? WaterMeters { get; set; }
            public DbSet<Customer>?   Customers   { get; set; }
        }
    }
  8. Since the database has changed, we need to update the data context.
    On the main menu of Microsoft Visual Studion, click Tools -> NuGet Package Manager -> Package Manager Console
  9. At the PMC prompt, type: Enable-Migrations and press Enter
  10. At the PMC prompt, type: Add-Migration Customers and press Enter
  11. At the PMC prompt, type: Update-Database and press Enter
  12. To create a folder, in the Solution Explorer, right-click the StellarWaterPoint5 project -> Add -> New Folder
  13. Type Customers as the name of the folder

Displaying Customers

It can be useful for a user to see a list of the consumers of a water services company. We will provide a form for that goal.

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 BorderStyle: FixedSingle
    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 StellarWaterPoint51.Models;
    
    namespace StellarWaterPoint51.Customers
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowCustomers()
            {
                StellarContext db      = new();
                List<Customer> clients = new();
    
                clients = db.Customers!.ToList();
    
                lvwCustomers.Items.Clear();
    
                foreach (Customer client in clients)
                {
                    ListViewItem lviCustomer = new ListViewItem(client.CustomerId.ToString());
    
                    lviCustomer.SubItems.Add(client.AccountNumber);
                    lviCustomer.SubItems.Add(client.AccountName);
                    lviCustomer.SubItems.Add(client.MeterNumber);
                    lviCustomer.SubItems.Add(client.AccountType);
                    lviCustomer.SubItems.Add(client.Address);
                    lviCustomer.SubItems.Add(client.City);
                    lviCustomer.SubItems.Add(client.County);
                    lviCustomer.SubItems.Add(client.State);
                    lviCustomer.SubItems.Add(client.ZIPCode);
    
                    lvwCustomers.Items.Add(lviCustomer);
                }
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                ShowCustomers();
            }
        }
    }
  11. In the Solution Explorer, double-click StellarManagement.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... FlatStyle: Flat
    Times New Roman, 24pt, style=Bold
  14. Double-click the C&ustomers
  15. Impliment the event as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53
    {
        public partial class StellarManagement : Form
        {
            public StellarManagement()
            {
                InitializeComponent();
    
                . . .
            }
    
            private void btnWaterBills_Click(object sender, EventArgs e)
            {
                
            }
            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();
            }
            
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }

A New Customer Account

Every entity that consumes the services of a water distribution company must have an account. We will provide a form from which a customer account can be set up.

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 FlatStyle: Flat
    Label Label   Meter &Details:  
    TextBox Text Box txtMeterDetails   Enabled: False
    Label Label   &Account Type:
    OTH - Other
    BUS - General Business
    RES - Residential Household
    SGO - Social/Government/Non-Profit Organization
    UUO - Unidentified or Unclassified Type of Organization
    WAT - Water Intensive Business (Laudromat, Hair Salon, Restaurant, etc
     
    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
    Button Button btnSaveCustomerAccount S&ave Customer Account FlatStyle: Flat
    Button Button btnClose &Close FlatStyle: Flat
  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:    btnCreateCustomerAccount
    CancelButton:    btnCancel
  6. Double-click the Find Water Meter button
  7. Implement the event as tollows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.Customers
    {
        public partial class Create : Form
        {
            public Create()
            {
                InitializeComponent();
            }
    
            private void btnFindWateMeter_Click(object sender, EventArgs e)
            {
                string strMeterNumber = mtbMeterNumber.Text.Replace("-", "").Trim();
    
                if (string.IsNullOrEmpty(strMeterNumber))
                {
                    MsgBox.Regular("You should first type a valid meter number, " +
                                   "and then click the Find Water Meter button.");
    
                    return;
                }
    
                StellarContext db = new();
                List<WaterMeter> meters = new();
    
                meters = db.WaterMeters!.ToList();
                WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == mtbMeterNumber.Text);
    
                txtMeterDetails.Text = meter!.Make + " " +
                                       meter.Model +
                                       " (Meter Size: " + meter.MeterSize + ")";
            }
        }
    }
  8. Return to the form and double-click the Save Customer Account button
  9. Implement the event as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.Customers
    {
        public partial class Create : Form
        {
            public Create()
            {
                InitializeComponent();
            }
    
            private void btnFindWateMeter_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void btnSaveCustomerAccount_Click(object sender, EventArgs e)
            {
                string strAccountNumber = mtbAccountNumber.Text.Replace("-", "").Trim();
    
                if (string.IsNullOrEmpty(strAccountNumber))
                {
                    MsgBox.Regular("You must type a (unique) account number. " +
                                   "Otherwise, the customer account cannot be created.");
                    return;
                }
    
                string strMeterNumber = mtbMeterNumber.Text.Replace("-", "").Trim();
    
                if (string.IsNullOrEmpty(strMeterNumber))
                {
                    MsgBox.Regular("You must type a meter number of the water meter to associate " +
                                   "to the customer account; otherwise, the account cannot be created.");
                    return;
                }
    
                StellarContext db = new();
    
                Customer client = new Customer()
                {
                    AccountNumber = mtbAccountNumber.Text,
                    AccountName = txtAccountName.Text,
                    MeterNumber = mtbMeterNumber.Text,
                    AccountType = cbxAccountsTypes.Text,
                    Address = txtAddress.Text,
                    City = txtCity.Text,
                    County = txtCounty.Text,
                    State = txtState.Text,
                    ZIPCode = mtbZIPCode.Text
                };
    
                db.Customers!.Add(client);
                db.SaveChanges();
    
                Close();
            }
        }
    }
  10. Return to the form and double-click the Close button
  11. Implement the event as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.Customers
    {
        public partial class Create : Form
        {
            public Create()
            {
                InitializeComponent();
            }
    
            private void btnFindWateMeter_Click(object sender, EventArgs e)
            {
                /* We want to check that the user had provided a water meter number.
                 * Since we are using a masked text box, and since its internal symbols 
                 * are counted as being part of the whole value, we need to remove those 
                 * symbols. We will also "trim" the value to remove the empty spaces. */
                string strMeterNumber = mtbMeterNumber.Text.Replace("-", "").Trim();
    
                // Make sure the user typed a (valid) water meter number.
                if (string.IsNullOrEmpty(strMeterNumber))
                {
                    MsgBox.Regular("You should first type a valid meter number, " +
                                   "and then click the Find Water Meter button.");
    
                    // If the user didn't type a water meter number, don't do nothing.
                    return;
                }
    
                // Get a reference to the EF context class
                StellarContext db = new();
                // Get a list that can contain the records of water meters
                List<WaterMeter> meters = new();
    
                // If some records of water meters exist, access them and store them in the List<> variable
                meters = db.WaterMeters!.ToList();
                /* If a list of water meters exists, find in it the water meter that has 
                 * the same meter number as the value the user had typed in the masked text box. */
                WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == mtbMeterNumber.Text);
    
                // If the water meter was found, put its values in the text boxes
                txtMeterDetails.Text = meter!.Make + " " +
                                       meter.Model +
                                       " (Meter Size: " + meter.MeterSize + ")";
            }
    
            private void btnSaveCustomerAccount_Click(object sender, EventArgs e)
            {
                /* We want to check that the user had provided a customer account number.
                 * Since we are using a masked text box, and since its internal symbols 
                 * are counted as being part of the whole value, we need to remove those 
                 * symbols. We will also "trim" the value to remove the empty spaces. */
                string strAccountNumber = mtbAccountNumber.Text.Replace("-", "").Trim();
    
                /* Make sure the user provides an account number. */
                if (string.IsNullOrEmpty(strAccountNumber))
                {
                    MsgBox.Regular("You must type a (unique) account number. " +
                                   "Otherwise, the customer account cannot be created.");
                    return;
                }
    
                string strMeterNumber = mtbMeterNumber.Text.Replace("-", "").Trim();
    
                if (string.IsNullOrEmpty(strMeterNumber))
                {
                    MsgBox.Regular("You must type a meter number of the water meter to associate " +
                                   "to the customer account; otherwise, the account cannot be created.");
                    return;
                }
    
                // Declare a variable for the Entity Framework database context
                StellarContext db = new();
    
                /* Get the values for a water meter from the New Water Meter form.
                 * Create a WaterMeter object using those values. */
                Customer client = new Customer()
                {
                    AccountNumber = mtbAccountNumber.Text,
                    AccountName = txtAccountName.Text,
                    MeterNumber = mtbMeterNumber.Text,
                    AccountType = cbxAccountsTypes.Text,
                    Address = txtAddress.Text,
                    City = txtCity.Text,
                    County = txtCounty.Text,
                    State = txtState.Text,
                    ZIPCode = mtbZIPCode.Text
                };
    
                // Add the created WaterMeter object to the collection of records in the application
                db.Customers!.Add(client);
                // Save the record to the database
                db.SaveChanges();
    
                Close();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  12. In the Solution Explorer, below the Customers folder, double-click Central.cs
  13. From the Toolbox, add a button to the form below the list view
  14. 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 FlatStyle: Flat
    &New Customer Account...
  15. On the Central form, double-click the New Customer Account button
  16. Implement the event as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.Customers
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowCustomers()
            {
                StellarContext db = new();
                List<Customer> clients = new();
    
                clients = db.Customers!.ToList();
    
                lvwCustomers.Items.Clear();
    
                foreach (Customer client in clients)
                {
                    ListViewItem lviCustomer = new ListViewItem(client.CustomerId.ToString());
    
                    lviCustomer.SubItems.Add(client.AccountNumber);
                    lviCustomer.SubItems.Add(client.AccountName);
                    lviCustomer.SubItems.Add(client.MeterNumber);
                    lviCustomer.SubItems.Add(client.AccountType);
                    lviCustomer.SubItems.Add(client.Address);
                    lviCustomer.SubItems.Add(client.City);
                    lviCustomer.SubItems.Add(client.County);
                    lviCustomer.SubItems.Add(client.State);
                    lviCustomer.SubItems.Add(client.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();
    
                create.ShowDialog();
    
                ShowCustomers();
            }
        }
    }
  17. To execute the application, on the main menu, click Debug -> Start Without Debugging:

    Stellar Water Point - New Customer Account

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

    Stellar Water Point - Customers Accounts

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

    Stellar Water Point - Customers Accounts

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

  24. Click Save Customer Account
  25. 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

  26. Close the forms and return to your programming environment
  27. In the Solution Explorer, double-click StellarManagement.cs to display the main form of the application
  28. Right-click the form and click View Code
  29. Change the StellarManagement() constructor as follows:
    using StellarWaterPoint53.Models;
    using System.Diagnostics.Metrics;
    
    namespace StellarWaterPoint53
    {
        public partial class StellarManagement : Form
        {
            public StellarManagement()
            {
                InitializeComponent();
    
                StellarContext db = new();
                /* 
                 */
    
                Customer client = new();
    
                
    
                db.SaveChanges();
            }
    
            private void btnWaterBills_Click(object sender, EventArgs e)
            {
                
            }
            
            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();
            }
            
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  30. To execute the application, on the main menu, click Debug -> Start Without Debugging
  31. Close the form and return to your programming environment
  32. Change the StellarManagement() constructor as follows:
    using StellarWaterPoint53.Models;
    using System.Diagnostics.Metrics;
    
    namespace StellarWaterPoint53
    {
        public partial class StellarManagement : Form
        {
            public StellarManagement()
            {
                InitializeComponent();
    
                StellarContext db = new();
                /* WaterMeter? meter = null;
    
                
                db.SaveChanges(); */
            }
    
            private void btnWaterBills_Click(object sender, EventArgs e)
            {
                
            }
            
            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();
            }
            
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }

Customer Account Details

To let a user view the details of an entity that consumes the services of a water distribution company, we will add a simple form.

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
    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 btnClose &Close FlatStyle: Flat 
  5. On the form, double-click the Find Customer Account button
  6. Implement the event as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.Customers
    {
        public partial class Details : Form
        {
            public Details()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                string strAccountNumber = mtbAccountNumber.Text.Replace("-", "").Trim();
    
                if (string.IsNullOrEmpty(strAccountNumber))
                {
                    MsgBox.Regular("You should first type a valid customer account number, " +
                                "and then click the Find Customer Account button.");
                    return;
                }
    
                StellarContext db = new();
                List<Customer> clients = new();
    
                clients = db.Customers!.ToList();
                Customer? client = clients.Find(cl => cl.AccountNumber == mtbAccountNumber.Text);
    
                txtAccountName.Text     = client!.AccountName;
                string? 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;
    
                List<WaterMeter> meters = new();
    
                meters = db.WaterMeters!.ToList();
                WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == strMeterNumber);
    
                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 StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.Customers
    {
        public partial class Details : Form
        {
            public Details()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                string strAccountNumber = mtbAccountNumber.Text.Replace("-", "").Trim();
    
                if (string.IsNullOrEmpty(strAccountNumber))
                {
                    MsgBox.Regular("You should first type a valid customer account number, " +
                                "and then click the Find Customer Account button.");
                    return;
                }
    
                StellarContext db       = new();
                List<Customer> clients  = new();
    
                clients                 = db.Customers!.ToList();
                Customer? client        = clients.Find(cl => cl.AccountNumber == mtbAccountNumber.Text);
    
                txtAccountName.Text     = client!.AccountName;
                string? 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;
    
                List<WaterMeter> meters = new();
    
                meters = db.WaterMeters!.ToList();
                WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == strMeterNumber);
    
                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 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 - Water Meters

    Control (Name) Other Properties
    ListView List View lvwWaterMeters No Change
    Button Button No Change No Change
    Button Button btnCustomerAccountDetails FlatStyle: Flat
    Customer Account &Details...
    Anchor: Bottom, Right
  12. Double-click the Customer Account &Details button
  13. Change the document as follows:
    using System.Data;
    using Microsoft.Data.SqlClient;
    
    namespace StellarWaterPoint21.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.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 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

If one or more pieces of information of a consumer changes, we will provide a form to assist the user to update the record.

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 FlatStyle: Flat 
    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 FlatStyle: Flat 
    Label Label   Meter &Details:  
    TextBox Text Box txtMeterDetails   Enabled: False
    Label Label   &Account Type:  
    ComboBox Combo Box cbxAccountsTypes  
    OTH - Other
    BUS - General Business
    RES - Residential Household
    SGO - Social/Government/Non-Profit Organization
    UUO - Unidentified or Unclassified Type of Organization
    WAT - Water Intensive Business (Laudromat, Hair Salon, Restaurant, etc
    Label Label   &Address:  
    TextBox Text Box txtAddress    
    Label Label   C&ity:  
    TextBox Text Box txtCity    
    Label Label   C&ounty:  
    TextBox Text Box txtCounty    
    Label Label   &State:  
    TextBox Text Box txtState    
    Label Label   &ZIP-Code:  
    MaskedTextBox Masked Text Box mtbZIPCode   Masked: Zip-Code
    Button Button btnUpdateCustomerAccount &Update Customer Account FlatStyle: Flat
    Button Button btnClose &Close FlatStyle: Flat
  5. Double-click the Find Customer Account button
  6. Implement the event as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.Customers
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                string strAccountNumber = mtbAccountNumber.Text.Replace("-", "").Trim();
    
                if (string.IsNullOrEmpty(strAccountNumber))
                {
                    MsgBox.Regular("You should first type a valid customer account number, " +
                                "and then click the Find Customer Account button.");
                    return;
                }
    
                StellarContext db       = new();
                List<Customer> clients  = new();
    
                clients                 = db.Customers!.ToList();
                Customer? client        = clients.Find(cl => cl.AccountNumber == mtbAccountNumber.Text);
    
                txtAccountName.Text     = client!.AccountName;
                mtbMeterNumber.Text     = client.MeterNumber;
                cbxAccountsTypes.Text   = client.AccountType;
                txtAddress.Text         = client.Address;
                txtCity.Text            = client.City;
                txtCounty.Text          = client.County;
                txtState.Text           = client.State;
                mtbZIPCode.Text         = client.ZIPCode;
    
                List<WaterMeter> meters = new();
    
                meters                  = db.WaterMeters!.ToList();
                WaterMeter? meter       = meters.Find(mtr => mtr.MeterNumber == mtbMeterNumber.Text);
    
                txtMeterDetails.Text    = meter!.Make + " " +
                                          meter.Model +
                                          " (Meter Size: " + meter.MeterSize + ")";
            }
    
            
        }
    }
  7. Return to the form and double-click the Find Water Meter button
  8. Implment the event as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.Customers
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void btnFindWateMeter_Click(object sender, EventArgs e)
            {
                string strMeterNumber = mtbMeterNumber.Text.Replace("-", "").Trim();
    
                if (string.IsNullOrEmpty(strMeterNumber))
                {
                    MsgBox.Regular("You should first type a valid meter number, " +
                                "and then click the Find Water Meter button.");
                    return;
                }
    
                StellarContext db  = new();
                List<WaterMeter> meters = new();
    
                meters = db.WaterMeters!.ToList();
                WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == mtbMeterNumber.Text);
    
                txtMeterDetails.Text = meter!.Make + " " +
                                       meter.Model +
                                       " (Meter Size: " + meter.MeterSize + ")";
            }
        }
    }
  9. Return to the form and double-click the Update Customer Account button
  10. Implement the event as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.Customers
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void btnFindWateMeter_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void btnUpdateCustomerAccount_Click(object sender, EventArgs e)
            {
                string strAccountNumber = mtbAccountNumber.Text.Replace("-", "").Trim();
    
                if (string.IsNullOrEmpty(strAccountNumber))
                {
                    MsgBox.Regular("You must first type the account number of the customer, " +
                                   "optionally change one or more values on the form, " +
                                   "and then click the Update Customer Account button.");
                    return;
                }
    
                StellarContext db      = new();
                List<Customer> clients = new();
    
                clients                = db.Customers!.ToList();
                Customer? client       = clients.Find(cl => cl.AccountNumber == mtbAccountNumber.Text);
    
                if(client is not null)
                {
                    client.AccountName = txtAccountName.Text;
                    client.MeterNumber = mtbMeterNumber.Text;
                    client.AccountType = cbxAccountsTypes.Text;
                    client.Address     = txtAddress.Text;
                    client.City        = txtCity.Text;
                    client.County      = txtCounty.Text;
                    client.State       = txtState.Text;
                    client.ZIPCode     = mtbZIPCode.Text;
                    
                    db.SaveChanges();
                }
    
                Close();
            }
        }
    }
  11. Return to the form and double-click the Close button
  12. Implement the event as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.Customers
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                /* Get the value from the Account Number text box.
                 * Remove the special characters, mostly the dashes. */
                string strAccountNumber = mtbAccountNumber.Text.Replace("-", "").Trim();
    
                // Make the user provided an account number
                if (string.IsNullOrEmpty(strAccountNumber))
                {
                    MsgBox.Regular("You should first type a valid customer account number, " +
                                "and then click the Find Customer Account button.");
                    return;
                }
    
                // Get a reference to the database context
                StellarContext db = new();
                // Prepare a list of customers records
                List<Customer> clients = new();
    
                /* Gather the Customers records, convert them into a list 
                 * and store it in the above list of customers records. */
                clients = db.Customers!.ToList();
                // Find out if the user provided an account number for an existing customer
                Customer? client = clients.Find(cl => cl.AccountNumber == mtbAccountNumber.Text);
    
                /* If the customer was found, get its values
                 * and display them in the controls on the form.*/
                txtAccountName.Text = client!.AccountName;
                mtbMeterNumber.Text = client.MeterNumber;
                cbxAccountsTypes.Text = client.AccountType;
                txtAddress.Text = client.Address;
                txtCity.Text = client.City;
                txtCounty.Text = client.County;
                txtState.Text = client.State;
                mtbZIPCode.Text = client.ZIPCode;
    
                // Prepare a list for water meters
                List<WaterMeter> meters = new();
    
                /* Gather the records, if any, of water meters, convert them 
                 * into a list, and store them in the prepared list of water meters. */
                meters = db.WaterMeters!.ToList();
                // Get the water meter associated with the selected customer
                WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == mtbMeterNumber.Text);
    
                // Display a summary of the details of the associated water meter
                txtMeterDetails.Text = meter!.Make + " " +
                                          meter.Model +
                                          " (Meter Size: " + meter.MeterSize + ")";
            }
    
            private void btnFindWateMeter_Click(object sender, EventArgs e)
            {
                /* If the user specified a different water meter, 
                 * display its values in the Water Meter Details text box.*/
                string strMeterNumber = mtbMeterNumber.Text.Replace("-", "").Trim();
    
                if (string.IsNullOrEmpty(strMeterNumber))
                {
                    MsgBox.Regular("You should first type a valid meter number, " +
                                "and then click the Find Water Meter button.");
                    return;
                }
    
                StellarContext db = new();
                List<WaterMeter> meters = new();
    
                meters = db.WaterMeters!.ToList();
                WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == mtbMeterNumber.Text);
    
                txtMeterDetails.Text = meter!.Make + " " +
                                       meter.Model +
                                       " (Meter Size: " + meter.MeterSize + ")";
            }
    
            private void btnUpdateCustomerAccount_Click(object sender, EventArgs e)
            {
                /* Make sure the user had provided a valid account number.
                 * If the Account Number text box is empty, don't do nothing. */
                string strAccountNumber = mtbAccountNumber.Text.Replace("-", "").Trim();
    
                if (string.IsNullOrEmpty(strAccountNumber))
                {
                    MsgBox.Regular("You must first type the account number of the customer, " +
                                   "optionally change one or more values on the form, " +
                                   "and then click the Update Customer Account button.");
                    return;
                }
    
                // Get the database context
                StellarContext db      = new();
                // Prepare a list of the customers account
                List<Customer> clients = new();
    
                /* Get the customers records.
                 * Convert them into a List<> list.
                 * Store that list in the above Lis<> variable. */
                clients                = db.Customers!.ToList();
                // Find a matching customer from the customers records
                Customer? client       = clients.Find(cl => cl.AccountNumber == mtbAccountNumber.Text);
    
                // If the customer was found, ...
                if (client is not null)
                {
                    /* Update the values of the customer account using
                     * the values from the controls on the form.       */
                    client.AccountName = txtAccountName.Text;
                    client.MeterNumber = mtbMeterNumber.Text;
                    client.AccountType = cbxAccountsTypes.Text;
                    client.Address     = txtAddress.Text;
                    client.City        = txtCity.Text;
                    client.County      = txtCounty.Text;
                    client.State       = txtState.Text;
                    client.ZIPCode     = mtbZIPCode.Text;
    
                    // Now that the record has changed, save the Customers table
                    db.SaveChanges();
                }
    
                // Return to the Central form that displays a list of customers
                Close();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  13. In the Solution Explorer, below the Customers folder, double-click Central.cs
  14. From the Toolbox, add a button to the form below the list view and on the right side of the Customer Account Editor button
  15. 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 FlatStyle: Flat
    &Update Customer Account...
    Anchor: Bottom, Right
  16. Display the Central form of the Customers folder
  17. Double-click the Update Customer Account button
  18. Change the document as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.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)
            {
                Create create = new();
    
                create.ShowDialog();
    
                ShowCustomers();
            }
    
            private void btnCustomerAccountDetails_Click(object sender, EventArgs e)
            {
                Details details = new();
    
                details.Show();
            }
    
            private void btnEditCustomerAccount_Click(object sender, EventArgs e)
            {
                Editor editor = new();
    
                editor.ShowDialog();
    
                ShowCustomers();
            }
        }
    }
  19. To execute the application, on the main menu, click Debug -> Start Without Debugging

    Stellar Water Point

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

    Stellar Water Point - Customers

  21. Click the Edit Customer Account button:

    Stellar Water Point - Water Meter Editor

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

    Stellar Water Point - Water Meter Editor

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

    Stellar Water Point - New Water Meter

  25. Click the Update Customer Account button:

    Stellar Water Point - Water Meters

  26. Close the forms and return to your programming environment

Deleting a Customer Account from the Database

When a consumer account becomes useless and must be removed from the system, we will create a form from which a user can delete an account.

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 FlatStyle: Flat 
    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 FlatStyle: Flat 
    Button Button btnClose &Close FlatStyle: Flat 
  5. On the form, double-click the Find Customer Account button
  6. Implement the event as tollows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.Customers
    {
        public partial class Delete : Form
        {
            public Delete()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                string strAccountNumber = mtbAccountNumber.Text.Replace("-", "").Trim();
    
                if (string.IsNullOrEmpty(strAccountNumber))
                {
                    MsgBox.Regular("You should first type a valid customer account number, " +
                                "and then click the Find Customer Account button.");
                    return;
                }
    
                StellarContext db = new();
                List<Customer> clients = new();
    
                clients = db.Customers!.ToList();
                Customer? client = clients.Find(cl => cl.AccountNumber == mtbAccountNumber.Text);
    
                txtAccountName.Text = client!.AccountName;
                string? 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;
    
                List<WaterMeter> meters = new();
    
                meters = db.WaterMeters!.ToList();
                WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == strMeterNumber);
    
                txtMeterDetails.Text = meter!.Make + " " +
                                          meter.Model +
                                          " (Meter Size: " + meter.MeterSize + ")";
            }
        }
    }
  7. Return to the form and double-click the Delete Customer Account button
  8. Implement the event as tollows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.Customers
    {
        public partial class Delete : Form
        {
            public Delete()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void btnDeleteCustomerAccount_Click(object sender, EventArgs e)
            {
                string strAccountNumber = mtbAccountNumber.Text.Replace("-", "").Trim();
    
                if (string.IsNullOrEmpty(strAccountNumber))
                {
                    MsgBox.Regular("You must enter a valid customer account number, " +
                                   "click the Find Customer Account button, " +
                                   "and then click the Delete Customer Account button.");
                    return;
                }
    
                StellarContext db = new();
                List<Customer> clients = new();
    
                clients = db.Customers!.ToList();
                Customer? client = clients.Find(cl => cl.AccountNumber == mtbAccountNumber.Text);
    
                if (client is not null)
                {
                    string strQuestion = "Are you sure you want to delete this " +
                                         "customer's account (the operation cannot be undone)?";
    
                    if (MessageBox.Show(strQuestion, "Stellar Water Point",
                                        MessageBoxButtons.YesNoCancel,
                                        MessageBoxIcon.Question) == DialogResult.Yes)
                    {
                        db.Customers!.Remove(client);
                        db.SaveChanges();
                    }
                }
    
                Close();
            }
        }
    }
  9. Return to the form and double-click the Close button
  10. Implement the event as tollows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.Customers
    {
        public partial class Delete : Form
        {
            public Delete()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                // Get the value from the Account Number text box
                string strAccountNumber = mtbAccountNumber.Text.Replace("-", "").Trim();
    
                /* If the user didn't provide an account number, let the user know and stop. */
                if (string.IsNullOrEmpty(strAccountNumber))
                {
                    MsgBox.Regular("You should first type a valid customer account number, " +
                                   "and then click the Find Customer Account button.");
                    return;
                }
    
                /* If the user provided a valid account number, get the associated 
                 * customer account and display the values in the controls on the form. */
                StellarContext db       = new();
                List<Customer> clients  = new();
    
                clients                 = db.Customers!.ToList();
                Customer? client        = clients.Find(cl => cl.AccountNumber == mtbAccountNumber.Text);
    
                txtAccountName.Text     = client!.AccountName;
                string? 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;
    
                List<WaterMeter> meters = new();
    
                meters                  = db.WaterMeters!.ToList();
                WaterMeter? meter       = meters.Find(mtr => mtr.MeterNumber == strMeterNumber);
    
                txtMeterDetails.Text    = meter!.Make + " " +
                                          meter.Model +
                                          " (Meter Size: " + meter.MeterSize + ")";
            }
    
            private void btnDeleteCustomerAccount_Click(object sender, EventArgs e)
            {
                /* Check that the user typed a valid customer account number. */
                string strAccountNumber = mtbAccountNumber.Text.Replace("-", "").Trim();
    
                // If the user didn't provide an account number, stop the operation.
                if (string.IsNullOrEmpty(strAccountNumber))
                {
                    MsgBox.Regular("You must enter a valid customer account number, " +
                                   "click the Find Customer Account button, " +
                                   "and then click the Delete Customer Account button.");
                    return;
                }
    
                // Get the records of the customers from the database
                StellarContext db = new();
                List<Customer> clients = new();
    
                clients = db.Customers!.ToList();
                /* From the records of customers, find a customer record that has the same 
                 * account number as the number the user typed in the Account Number masked text box*/
                Customer? client = clients.Find(cl => cl.AccountNumber == mtbAccountNumber.Text);
    
                // If such a customer was found, first ask the user to confirm
                if (client is not null)
                {
                    string strQuestion = "Are you sure you want to delete this " +
                                         "customer's account (the operation cannot be undone)?";
    
                    // If the user has confirmed that he/she wants to delete the account, ...
                    if (MessageBox.Show(strQuestion, "Stellar Water Point",
                                        MessageBoxButtons.YesNoCancel,
                                        MessageBoxIcon.Question) == DialogResult.Yes)
                    {
                        //... then delete the account
                        db.Customers!.Remove(client);
                        // Now that the table has changed, save it
                        db.SaveChanges();
                    }
                }
    
                // Return to the Customers.Central form that displays the customers records
                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 FlatStyle: Flat
    Create Customer &Account....
    Anchor: Bottom, Right
    Button Button btnCustomerAccountDetails FlatStyle: Flat
    Customer Account &Details...
    Anchor: Bottom, Right
    Button Button btnEditCustomerAccount FlatStyle: Flat
    &Edit Customer Account...
    Anchor: Bottom, Right
    Button Button btnDeleteCustomerAccount FlatStyle: Flat
    &Delete Customer Account...
    Anchor: Bottom, Right
    Button Button btnClose FlatStyle: Flat
    &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 StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.Customers
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowCustomers()
            {
                StellarContext db = new();
                List<Customer> clients = new();
    
                clients = db.Customers!.ToList();
    
                lvwCustomers.Items.Clear();
    
                foreach (Customer client in clients)
                {
                    ListViewItem lviCustomer = new ListViewItem(client.CustomerId.ToString());
    
                    lviCustomer.SubItems.Add(client.AccountNumber);
                    lviCustomer.SubItems.Add(client.AccountName);
                    lviCustomer.SubItems.Add(client.MeterNumber);
                    lviCustomer.SubItems.Add(client.AccountType);
                    lviCustomer.SubItems.Add(client.Address);
                    lviCustomer.SubItems.Add(client.City);
                    lviCustomer.SubItems.Add(client.County);
                    lviCustomer.SubItems.Add(client.State);
                    lviCustomer.SubItems.Add(client.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();
    
                create.ShowDialog();
    
                ShowCustomers();
            }
    
            private void btnCustomerAccountDetails_Click(object sender, EventArgs e)
            {
                Details details = new();
    
                details.Show();
            }
    
            private void btnEditCustomerAccount_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
  23. Read the text on the message box.
    On the message box, click Yes

    Stellar Water Point - Customers

  24. Close the forms and return to your programming environment

Water Bills

Introduction

A water distribution company must create water bills to present some information about what consumers had used as a service. Of courses, such bills must be designed, created, and presented. We will take care of that.

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 WaterBill
  4. Click Add
  5. Change the code as follows:
    namespace StellarWaterPoint5.Models
    {
        public class WaterBill
        {
            [Key]
            public int      WaterBillId           { get; set; }
            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; }
        }
    }
  6. In the Solution Explorer, below Models, double-click the StellarContext.cs file
  7. Change the class as follows:
    using System.Data.Entity;
    
    namespace StellarWaterPoint51.Models
    {
        public class StellarContext : DbContext
        {
            public DbSet<WaterMeter>? WaterMeters { get; set; }
            public DbSet<Customer>?   Customers   { get; set; }
            public DbSet<WaterBill>?  WaterBills  { get; set; }
        }
    }
  8. Since the database has changed, we need to update the data context.
    On the main menu of Microsoft Visual Studion, click Tools -> NuGet Package Manager -> Package Manager Console
  9. At the PMC prompt, type: Add-Migration WaterBills and press Enter
  10. At the PMC prompt, type: Update-Database and press Enter
  11. To create another class, in the Solution Explorer, right-click Models -> Add -> Class...
  12. Type WaterBillManager as the Name of the file
  13. Click Add
  14. Define the class as follows:
    namespace StellarWaterPoint21.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);
    
                if (acnt == "RES - Residential Household")
                {
                    results.tier1 = total * 41.50 / 10000.00;
                    results.tier2 = total * 32.50 / 10000.00;
                    results.tier3 = total * 26.00 / 10000.00;
                }
                else if (acnt == "SGO - Social/Government/Non-Profit Organization")
                {
                    results.tier1 = total * 46.00 / 10000.00;
                    results.tier2 = total * 50.00 / 10000.00;
                    results.tier3 = total * 4.00  / 10000.00;
                }
                else if (acnt == "BUS - General Business")
                {
                    results.tier1 = total * 45.00 / 10000.00;
                    results.tier2 = total * 30.00 / 10000.00;
                    results.tier3 = total * 25.00 / 10000.00;
                }
                else if (acnt == "UUO - Unidentified or Unclassified Type of Organization")
                {
                    results.tier1 = total * 25.00 / 10000.00;
                    results.tier2 = total * 35.00 / 10000.00;
                    results.tier3 = total * 40.00 / 10000.00;
                }
                else if (acnt == "WAT - Water Intensive Business(Laudromat, Hair Salon, Restaurant, etc")
                {
                    results.tier1 = total * 50.00 / 10000.00;
                    results.tier2 = total * 40.00 / 10000.00;
                    results.tier3 = total * 10.00 / 10000.00;
                }
                else
                {
                    results.tier1 = total * (48.00 / 10000.00);
                    results.tier2 = total * (32.00 / 10000.00);
                    results.tier3 = total * (20.00 / 10000.00);
                }
    
                return results;
            }
    
            internal static double CalculateSewerCharges(string acnt, double total)
            {
                double result;
    
                if (acnt == "RES - Residential Household")
                {
                    result = total * 6.826941 / 100.00;
                }
                else if (acnt == "SGO - Social/Government/Non-Profit Organization")
                {
                    result = total * 4.162522 / 100.00;
                }
                else if (acnt == "BUS - General Business")
                {
                    result = total * 8.315136 / 100.00;
                }
                else if (acnt == "UUO - Unidentified or Unclassified Type of Organization")
                {
                    result = total * 10.626147 / 100.00;
                }
                else if (acnt == "WAT - Water Intensive Business(Laudromat, Hair Salon, Restaurant, etc")
                {
                    result = total * 12.025135 / 100.00;
                }
                else // if (acnt == "OTH - Other")
                {
                    result = total * 9.202615 / 100.00;
                }
    
                return result;
            }
    
            internal static double CalculateEnvironmentCharges(string acnt, double total)
            {
                double result;
    
                switch (acnt)
                {
                    case "RES - Residential Household":
                        result = total * 0.022724;
                        break;
                    case "SGO - Social/Government/Non-Profit Organization":
                        result = total * 0.118242;
                        break;
                    case "BUS - General Business":
                        result = total * 0.161369;
                        break;
                    case "UUO - Unidentified or Unclassified Type of Organization":
                        result = total * 0.082477;
                        break;
                    case "WAT - Water Intensive Business(Laudromat, Hair Salon, Restaurant, etc":
                        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 - Residential Household":
                        return total * 0.145748;
                    case "SGO - Social/Government/Non-Profit Organization":
                        return total * 0.102246;
                    case "BUS - General Business":
                        return total * 0.242627;
                    case "UUO - Unidentified or Unclassified Type of Organization":
                        return total * 0.186692;
                    case "WAT - Water Intensive Business(Laudromat, Hair Salon, Restaurant, etc":
                        return total * 0.412628;
                    default:
                        return total * 0.210248;
                }
            }
    
            internal static double CalculateLocalTaxes(string acnt, double total) => acnt switch
            {
                "RES - Residential Household" => total * 0.031574,
                "SGO - Social/Government/Non-Profit Organization" => total * 0.035026,
                "BUS - General Business" => total * 0.122517,
                "UUO - Unidentified or Unclassified Type of Organization" => total * 0.105737,
                "WAT - Water Intensive Business(Laudromat, Hair Salon, Restaurant, etc" => total * 0.153248,
                _     => total * 0.125148
            };
    
            internal static double CalculateStateTaxes(string acnt, double total) => acnt switch
            {
                "RES - Residential Household" => total * 0.017242,
                "SGO - Social/Government/Non-Profit Organization" => total * 0.008779,
                "BUS - General Business" => total * 0.042448,
                "UUO - Unidentified or Unclassified Type of Organization" => total * 0.067958,
                "WAT - Water Intensive Business(Laudromat, Hair Salon, Restaurant, etc" => 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 - Residential Household")
                {
                    tsPaymentDueDate = new TimeSpan(15, 0, 0, 0);
                }
                else if (acnt == "SGO - Social/Government/Non-Profit Organization")
                {
                    tsPaymentDueDate = new TimeSpan(20, 0, 0, 0);
                }
                else if (acnt == "BUS - General Business")
                {
                    tsPaymentDueDate = new TimeSpan(30, 0, 0, 0);
                }
                else if (acnt == "UUO - Unidentified or Unclassified Type of Organization")
                {
                    tsPaymentDueDate = new TimeSpan(25, 0, 0, 0);
                }
                else if (acnt == "WAT - Water Intensive Business(Laudromat, Hair Salon, Restaurant, etc")
                {
                    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 - Residential Household":
                        return date + new TimeSpan(30, 0, 0, 0);
                    case "SGO - Social/Government/Non-Profit Organization":
                        return date + new TimeSpan(40, 0, 0, 0);
                    case "BUS - General Business":
                        return date + new TimeSpan(50, 0, 0, 0);
                    case "UUO - Unidentified or Unclassified Type of Organization":
                        return date + new TimeSpan(60, 0, 0, 0);
                    case "WAT - Water Intensive Business(Laudromat, Hair Salon, Restaurant, etc":
                        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 - Residential Household" => amt + 8.95,
                "SGO - Social/Government/Non-Profit Organization" => amt + (amt /  4.575),
                "BUS - General Business" => amt + (amt / 12.315),
                "UUO - Unidentified or Unclassified Type of Organization" => amt + (amt /  7.425),
                "WAT - Water Intensive Business(Laudromat, Hair Salon, Restaurant, etc" => amt + (amt / 15.225),
                _     => amt + (amt / 6.735)
            };
        }
    }
  15. To create a folder, in the Solution Explorer, right-click the StellarWaterPoint2 project -> Add -> New Folder
  16. Type WaterBills as the name of the folder

Showing Water Bills

A typical water distribution application has many customers and each customer has a tremendous number of water bills. Some time to time, a user may want to see a list of water bills. We will create a form to make it possible.

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
    Anchor: Top, Bottom, Left, Right
  9. Double-click an unoccupied area of the form to generate its Load event
  10. Change the document as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.WaterBills
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowWaterBills()
            {
                StellarContext db = new();
                List<Customer>  clients = [.. db.Customers!];
                List<WaterBill> bills   = [.. db.WaterBills!];
    
                lvwWaterBills.Items.Clear();
    
                foreach (WaterBill bill in bills)
                {
                    ListViewItem lviWaterBill = new ListViewItem(bill.WaterBillId.ToString());
    
                    lviWaterBill.SubItems.Add(bill.BillNumber.ToString());
                    Customer? client = clients.Find(cl => cl.AccountNumber == bill.AccountNumber);
    
                    lviWaterBill.SubItems.Add(bill.AccountNumber + " - " +
                                              client!.AccountName +
                                              ", Type: " + client.AccountType![..3] +
                                              ", (Mtr #: " + client.MeterNumber + ")");
    
                    lviWaterBill.SubItems.Add(bill.MeterReadingStartDate.ToShortDateString());
                    lviWaterBill.SubItems.Add(bill.MeterReadingEndDate.ToShortDateString());
                    lviWaterBill.SubItems.Add(bill.BillingDays.ToString());
                    lviWaterBill.SubItems.Add(bill.CounterReadingStart.ToString());
                    lviWaterBill.SubItems.Add(bill.CounterReadingEnd.ToString());
                    lviWaterBill.SubItems.Add(bill.TotalHCF.ToString());
                    lviWaterBill.SubItems.Add(bill.TotalGallons.ToString());
                    lviWaterBill.SubItems.Add(bill.PaymentDueDate.ToShortDateString());
                    lviWaterBill.SubItems.Add(bill.AmountDue.ToString());
    
                    lvwWaterBills.Items.Add(lviWaterBill);
                }
            }
    
            private void Central_Load(object sender, EventArgs e)
            {
                ShowWaterBills();
            }
        }
    }
    
  11. In the Solution Explorer, double-click StellarManagement.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... FlatStyle: Flat
    Times New Roman, 24pt, style=Bold
    Button Button btnClose &Close FlatStyle: Flat
    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:
    namespace StellarWaterPoint21
    {
        public partial class StellarManagement : Form
        {
            public StellarManagement()
            {
                InitializeComponent();
            }
    
            private void btnWaterBills_Click(object o, EventArgs e)
            {
                WaterBills.Central central = new();
    
                central.Show();
            }
    
            private void btnCustomers_Click(object o, EventArgs e)
            {
                Customers.Central clients = new();
    
                clients.ShowDialog();
            }
    
            private void btnWaterMeters_Click(object o, EventArgs e)
            {
                WaterMeters.Central central = new WaterMeters.Central();
    
                central.ShowDialog();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }

A New Water Bill

As mentioned already, a water bill must be created and some other aspects, such as calculations, must be taken into consideration. We will create a form that a user can use for that goal.

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 FlatStyle: Flat 
    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 FlatStyle: Flat
    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  
    Button Button Save Water Bill btnSaveWaterBill FlatStyle: Flat 
    Button Button &Close btnClose FlatStyle: Flat 

    Form Properties

    Form Property Value
    FormBorderStyle FixedDialog
    Text Stellar Water Point - Water Bill Processing
    StartPosition CenterScreen
    MaximizeBox False
    MinimizeBox False
  5. On the form, double-click the Find Customer Account button
  6. Change the document as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.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.Regular("You should first type a valid customer account number, " +
                                "and then click the Find Customer Account button.");
                    return;
                }
    
                StellarContext db = new();
                List<Customer> clients = new();
    
                clients = db.Customers!.ToList();
                Customer? client = clients.Find(cl => cl.AccountNumber == mtbAccountNumber.Text);
    
                txtAccountName.Text = client!.AccountName;
                string? 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;
    
                List<WaterMeter> meters = new();
    
                meters = db.WaterMeters!.ToList();
                WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == strMeterNumber);
    
                txtMeterDetails.Text = meter!.Make + " " +
                                          meter.Model +
                                          " (Meter Size: " + meter.MeterSize + ")";
            }
        }
    }
  7. Return to the form and double-click the Meter Reading End Date date time picker to generate its Value Changed event
  8. Implement the event as follows:
    using System.Data;
    using Microsoft.Data.SqlClient;
    
    namespace StellarWaterPoint5.WaterBills
    {
        public partial class Create : Form
        {
            public Create()
            {
                InitializeComponent();
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void dtpMeterReadingEndDate_ValueChanged(object sender, EventArgs e)
            {
                TimeSpan tsDays = dtpMeterReadingEndDate.Value - dtpMeterReadingStartDate.Value;
    
                txtBillingDays.Text = (tsDays.Days + 1).ToString();
            }
        }
    }
  9. Return to the form and double-click the Evaluate Water Bill button
  10. Implement the event as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.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)
                {
                    MessageBox.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)
                {
                    MessageBox.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");
            }
        }
    }
  11. Return to the form and double-click the Save Water Bill button
  12. Return to the form and double-click the Close button to generate its Click event
  13. Implement the events as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.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.Regular("You should first type a valid customer account number, " +
                                "and then click the Find Customer Account button.");
                    return;
                }
    
                StellarContext db = new();
                List<Customer> clients = new();
    
                clients = db.Customers!.ToList();
                Customer? client = clients.Find(cl => cl.AccountNumber == mtbAccountNumber.Text);
    
                txtAccountName.Text = client!.AccountName;
                string? 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;
    
                List<WaterMeter> meters = new();
    
                meters = db.WaterMeters!.ToList();
                WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == strMeterNumber);
    
                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)
                {
                    MessageBox.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)
                {
                    MessageBox.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.Regular("You must type a (unique) bill number for the " +
                                    "water bill you are processing.");
                    return;
                }
    
                string strAccountNumber = mtbAccountNumber.Text.Replace("-", "").Trim();
    
                if (string.IsNullOrEmpty(strAccountNumber))
                {
                    MsgBox.Regular("You should first type a valid customer account number, " +
                                "and then click the Find Customer Account button.");
                    return;
                }
    
                StellarContext db = new();
    
                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)
                };
    
                db.WaterBills!.Add(bill);
                db.SaveChanges();
    
                Close();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  14. In the Solution Explorer, below the WaterBills folder, double-click Central.cs
  15. From the Toolbox, add a button to the form below the list view
  16. 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 FlatStyle: Flat
    &Process Water Bill...
  17. On the Central form, double-click the Process Water Bill button
  18. 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();
            }
        }
    }
  19. To execute the application, on the main menu, click Debug -> Start Without Debugging:

    Stellar Water Point - New Customer Account

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

    Stellar Water Point - Water Bills

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

    Stellar Water Point - Create Water Bill

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

    Stellar Water Point - Create Water Bill

    Stellar Water Point - Create Water Bill

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

    Stellar Water Point - Customers

  23. Close the forms and return to your programming environment

Water Bill Details

As mentioned already, a water bill includes many pieces of information. To make it possible for a user to simply view that information, we will create a form that can be used to view the details of a water bill.

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

    Form Properties

    Form Property Value
    FormBorderStyle FixedDialog
    Text Stellar Water Point - Water Bill Processing
    StartPosition CenterScreen
    MaximizeBox False
    MinimizeBox False
  5. On the form, double-click the Find Water Bill button
  6. Implement the event as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.WaterBills
    {
        public partial class Details : Form
        {
            public Details()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterBill_Click(object sender, EventArgs e)
            {
                if (string.IsNullOrEmpty(txtBillNumber.Text))
                {
                    MsgBox.Regular("You must type a (valid) water bill number, " +
                                   "and then click the Find Water Bill button.");
                    return;
                }
    
                StellarContext db = new();
    
                try
                {
                    int billNbr                       = int.Parse(txtBillNumber.Text);
    
                    List<WaterBill> bills             = db.WaterBills!.ToList();
    
                    try
                    {
                        WaterBill? bill               = bills.Find(bl => bl.BillNumber == billNbr);
    
                        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();
                        txtAmountDue.Text             = bill.AmountDue.ToString();
                        txtPaymentDueDate.Text        = bill.PaymentDueDate.ToLongDateString();
                        txtLateAmountDue.Text         = bill.LateAmountDue.ToString();
                        txtLatePaymentDueDate.Text    = bill.LatePaymentDueDate.ToLongDateString();
    
                        List<Customer> clients        = db.Customers!.ToList();
                        Customer? client              = clients.Find(cl => cl.AccountNumber == txtAccountNumber.Text);
    
                        txtAccountName.Text           = client!.AccountName;
                        string? 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;
    
                        List<WaterMeter> meters       = db.WaterMeters!.ToList();
                        WaterMeter? meter             = meters.Find(mtr => mtr.MeterNumber == strMeterNumber);
    
                        txtMeterDetails.Text          = meter!.Make + " " +
                                                        meter.Model +
                                                        " (Meter Size: " + meter.MeterSize + ")";
                    }
                    catch(NullReferenceException nre)
                    {
                        MsgBox.Regular("The number you typed doesn't match " +
                                       "any of the water bill numbers in our system." + Environment.NewLine +
                                       "The error produced was: " + nre.Message);
                    }
                }
                catch (FormatException fe)
                {
                    MsgBox.Regular("You must type a valid water bill number." + Environment.NewLine +
                                   "The error produced was: " + fe.Message);
                }
                catch(Exception ex)
                {
                    MsgBox.Regular("Something went wrong trying to get water bill." + Environment.NewLine +
                                   "The error produced was: " + ex.Message);
                }
            }
        }
    }
  7. Return to the form and double-click the Close button
  8. Implement the event as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.WaterBills
    {
        public partial class Details : Form
        {
            public Details()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterBill_Click(object sender, EventArgs e)
            {
                /* Before doing anything, first find out whether the user entered 
                 * some value in the bill number text box. */
                if (string.IsNullOrEmpty(txtBillNumber.Text))
                {
                    // If the Bill Number text box is empty, ...
                    MsgBox.Regular("You must type a (valid) water bill number, " +
                                   "and then click the Find Water Bill button.");
                    // There is nothing to do. So, stop!
                    return;
                }
    
                /* Use Exception Handling in anticipation of bad occurrences.
                 * Check the "catch" sections. */
                try
                {
                    // Get a reference to the database context
                    StellarContext db                 = new();
    
                    // Get the value that the user typed. Consider it an integer
                    int billNbr                       = int.Parse(txtBillNumber.Text);
    
                    /* Get a list of water bills, convert it to a List<> object, 
                     * and store it in a List<> variable named bills. */
                    List<WaterBill> bills             = db.WaterBills!.ToList();
    
                    try
                    {
                        /* Using the list of water bills, find a water bill 
                         * whose number is the same as the number the user typed. */
                        WaterBill? bill               = bills.Find(bl => bl.BillNumber == billNbr);
    
                        // If a water bill was found, get its values and display them in the text boxes on the form.
                        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();
                        txtAmountDue.Text             = bill.AmountDue.ToString();
                        txtPaymentDueDate.Text        = bill.PaymentDueDate.ToLongDateString();
                        txtLateAmountDue.Text         = bill.LateAmountDue.ToString();
                        txtLatePaymentDueDate.Text    = bill.LatePaymentDueDate.ToLongDateString();
    
                        // Get the details of the customer whose bill this is, and display them in the text boxes
                        List<Customer> clients        = db.Customers!.ToList();
                        Customer? client              = clients.Find(cl => cl.AccountNumber == txtAccountNumber.Text);
    
                        txtAccountName.Text           = client!.AccountName;
                        string? 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;
    
                        // Get the details of the water meter that the cusomter is using, ...
                        List<WaterMeter> meters       = db.WaterMeters!.ToList();
                        WaterMeter? meter             = meters.Find(mtr => mtr.MeterNumber == strMeterNumber);
    
                        // and display those details in the Meter Details text box
                        txtMeterDetails.Text          = meter!.Make + " " +
                                                        meter.Model +
                                                        " (Meter Size: " + meter.MeterSize + ")";
                    }
                    catch (NullReferenceException nre)
                    {
                        /* If the user typed some digits, find out whether that number corresponds to 
                         * a valid water bill number. If the number the user typed doesn't match 
                         * any bill number, then the application produced a NullReferenceException exception */
                        MsgBox.Regular("The number you typed doesn't match " +
                                       "any of the water bill numbers in our system." + Environment.NewLine +
                                       "The error produced was: " + nre.Message);
                    }
                }
                catch (FormatException fe)
                {
                    /* The bill number is an integer. If the user typed anything other  
                     *than digits, then the application produced a FormatException exception. */
                    MsgBox.Regular("You must type a valid water bill number." + Environment.NewLine +
                                   "The error produced was: " + fe.Message);
                }
                catch (Exception ex)
                {
                    MsgBox.Regular("Something went wrong trying to get water bill." + Environment.NewLine +
                                   "The error produced was: " + ex.Message);
                }
            }
    
            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 FlatStyle: Flat
    Water Bill &Details...
    Anchor: Bottom, Right
  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

    Stellar Water Point - View Water Bill

  18. Click the Find Water Bill button:

    Stellar Water Point - View Water Bill

  19. Close the forms and return to your programming environment

A Water Bill Update

There can be errors or inconsistencies in a water bill. When necessary, such errors or inconsistencies must be corrected. We will create a form that can be used for that.

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 Additional Properties
    Button Button btnFindWaterBill &Find FlatStyle: Flat 
    Button Button btnUpdateWaterBill &Update Water Bill FlatStyle: Flat 
  8. On the form, double-click Find Water Bill button
  9. Change the document as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.WaterBills
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterBill_Click(object sender, EventArgs e)
            {
                if (string.IsNullOrEmpty(txtBillNumber.Text))
                {
                    MsgBox.Regular("You must type a (valid) water bill number, " +
                                   "and then click the Find Water Bill button.");
                    return;
                }
    
                try
                {
                    StellarContext db = new();
    
                    int billNbr = int.Parse(txtBillNumber.Text);
    
                    List<WaterBill> bills = db.WaterBills!.ToList();
    
                    try
                    {
                        WaterBill? bill = bills.Find(bl => bl.BillNumber == billNbr);
    
                        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();
                        txtAmountDue.Text = bill.AmountDue.ToString();
                        dtpPaymentDueDate.Value = bill.PaymentDueDate;
                        txtLateAmountDue.Text = bill.LateAmountDue.ToString();
                        dtpLatePaymentDueDate.Value = bill.LatePaymentDueDate;
    
                        List<Customer> clients = db.Customers!.ToList();
                        Customer? client = clients.Find(cl => cl.AccountNumber == mtbAccountNumber.Text);
    
                        txtAccountName.Text = client!.AccountName;
                        string? 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;
    
                        List<WaterMeter> meters = db.WaterMeters!.ToList();
                        WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == strMeterNumber);
    
                        txtMeterDetails.Text = meter!.Make + " " +
                                                        meter.Model +
                                                        " (Meter Size: " + meter.MeterSize + ")";
                    }
                    catch (NullReferenceException nre)
                    {
                        MsgBox.Regular("The number you typed doesn't match " +
                                       "any of the water bill numbers in our system." + Environment.NewLine +
                                       "The error produced was: " + nre.Message);
                    }
                }
                catch (FormatException fe)
                {
                    MsgBox.Regular("You must type a valid water bill number." + Environment.NewLine +
                                   "The error produced was: " + fe.Message);
                }
                catch (Exception ex)
                {
                    MsgBox.Regular("Something went wrong trying to get water bill." + Environment.NewLine +
                                   "The error produced was: " + ex.Message);
                }
            }
        }
    }
  10. Return to the form and double-click the Find Customer Account button
  11. Implement the event as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.WaterBills
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterBill_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                string strAccountNumber = mtbAccountNumber.Text.Replace("-", "").Trim();
    
                if (string.IsNullOrEmpty(strAccountNumber))
                {
                    MsgBox.Regular("You should first type a valid customer account number, " +
                                "and then click the Find Customer Account button.");
                    return;
                }
    
                StellarContext db = new();
                List<Customer> clients = new();
    
                clients = db.Customers!.ToList();
                Customer? client = clients.Find(cl => cl.AccountNumber == mtbAccountNumber.Text);
    
                txtAccountName.Text = client!.AccountName;
                string? 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;
    
                List<WaterMeter> meters = new();
    
                meters = db.WaterMeters!.ToList();
                WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == strMeterNumber);
    
                txtMeterDetails.Text = 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:
    using System.Data;
    using Microsoft.Data.SqlClient;
    
    namespace StellarWaterPoint21.WaterBills
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterBill_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void dtpMeterReadingEndDate_ValueChanged(object sender, EventArgs e)
            {
                TimeSpan tsDays = dtpMeterReadingEndDate.Value - dtpMeterReadingStartDate.Value;
    
                txtBillingDays.Text = (tsDays.Days + 1).ToString();
            }
        }
    }
  14. Return to the form and double-click the Evaluate Water Bill button
  15. Implement the event as follows:
    using StellarWaterPoint2.Models;
    using System.Text.Json;
    
    namespace StellarWaterPoint2.WaterBills
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterBill_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void dtpMeterReadingEndDate_ValueChanged(object sender, EventArgs e)
            {
                TimeSpan tsDays = dtpMeterReadingEndDate.Value - dtpMeterReadingStartDate.Value;
    
                txtBillingDays.Text = (tsDays.Days + 1).ToString();
            }
    
            private void btnEvaluateWaterBill_Click(object sender, EventArgs e)
            {
                double counterStart = 0, counterEnd = 0;
    
                try
                {
                    counterStart = double.Parse(txtCounterReadingStart.Text);
                }
                catch (FormatException feCRStart)
                {
                    MessageBox.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)
                {
                    MessageBox.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");
            }
        }
    }
  16. Return to the form and double-click the Update Water Bill button
  17. Implement the event as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.WaterBills
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterBill_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void dtpMeterReadingEndDate_ValueChanged(object sender, EventArgs e)
            {
                TimeSpan tsDays = dtpMeterReadingEndDate.Value - dtpMeterReadingStartDate.Value;
    
                txtBillingDays.Text = (tsDays.Days + 1).ToString();
            }
    
            private void btnEvaluateWaterBill_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void btnUpdateWaterBill_Click(object sender, EventArgs e)
            {
                if (string.IsNullOrEmpty(txtBillNumber.Text))
                {
                    MsgBox.Regular("You must type a (unique) bill number for the " +
                                    "water bill you are processing.");
                    return;
                }
    
                string strAccountNumber = mtbAccountNumber.Text.Replace("-", "").Trim();
    
                if (string.IsNullOrEmpty(strAccountNumber))
                {
                    MsgBox.Regular("You should first type a valid customer account number, " +
                                "and then click the Find Customer Account button.");
                    return;
                }
    
                int billNbr = int.Parse(txtBillNumber.Text);
    
                StellarContext db = new();
                List<WaterBill> bills = db.WaterBills!.ToList();
                WaterBill? bill = bills.Find(bl => bl.BillNumber == billNbr);
    
                if(bill is null)
                {
                    MsgBox.Regular("There is no water bill with the bill number you typed.");
                    return;
                }
    
                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);
    
                db.SaveChanges();
    
                Close();
            }
        }
    }Close();
  18. Return to the form and double-click the Close button
  19. Implement the event as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.WaterBills
    {
        public partial class Editor : Form
        {
            public Editor()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterBill_Click(object sender, EventArgs e)
            {
                /* Before doing anything, first find out whether the user entered 
                 * some value in the bill number text box. */
                if (string.IsNullOrEmpty(txtBillNumber.Text))
                {
                    // If the Bill Number text box is empty, ...
                    MsgBox.Regular("You must type a (valid) water bill number, " +
                                   "and then click the Find Water Bill button.");
                    // There is nothing to do. So, stop!
                    return;
                }
    
                /* Use Exception Handling in anticipation of bad occurrences.
                 * Check the "catch" sections. */
                try
                {
                    // Get a reference to the database context
                    StellarContext db = new();
    
                    // Get the value that the user typed. Consider it an integer
                    int billNbr = int.Parse(txtBillNumber.Text);
    
                    /* Get a list of water bills, convert it to a List<> object, 
                     * and store it in a List<> variable named bills. */
                    List<WaterBill> bills = db.WaterBills!.ToList();
    
                    try
                    {
                        /* Using the list of water bills, find a water bill 
                         * whose number is the same as the number the user typed. */
                        WaterBill? bill = bills.Find(bl => bl.BillNumber == billNbr);
    
                        // If a water bill was found, get its values and display them in the controls on the form.
                        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();
                        txtAmountDue.Text = bill.AmountDue.ToString();
                        dtpPaymentDueDate.Value = bill.PaymentDueDate;
                        txtLateAmountDue.Text = bill.LateAmountDue.ToString();
                        dtpLatePaymentDueDate.Value = bill.LatePaymentDueDate;
    
                        // Get the details of the customer whose bill this is, and display them in the text boxes
                        List<Customer> clients = db.Customers!.ToList();
                        Customer? client = clients.Find(cl => cl.AccountNumber == mtbAccountNumber.Text);
    
                        txtAccountName.Text = client!.AccountName;
                        string? 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;
    
                        // Get the details of the water meter that the cusomter is using, ...
                        List<WaterMeter> meters = db.WaterMeters!.ToList();
                        WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == strMeterNumber);
    
                        // and display those details in the Meter Details text box
                        txtMeterDetails.Text = meter!.Make + " " +
                                                        meter.Model +
                                                        " (Meter Size: " + meter.MeterSize + ")";
                    }
                    catch (NullReferenceException nre)
                    {
                        /* If the user typed some digits, find out whether that number corresponds to 
                         * a valid water bill number. If the number the user typed doesn't match 
                         * any bill number, then the application produced a NullReferenceException exception */
                        MsgBox.Regular("The number you typed doesn't match " +
                                       "any of the water bill numbers in our system." + Environment.NewLine +
                                       "The error produced was: " + nre.Message);
                    }
                }
                catch (FormatException fe)
                {
                    /* The bill number is an integer. If the user typed anything other  
                     *than digits, then the application produced a FormatException exception. */
                    MsgBox.Regular("You must type a valid water bill number." + Environment.NewLine +
                                   "The error produced was: " + fe.Message);
                }
                catch (Exception ex)
                {
                    MsgBox.Regular("Something went wrong trying to get water bill." + Environment.NewLine +
                                   "The error produced was: " + ex.Message);
                }
            }
    
            private void btnFindCustomerAccount_Click(object sender, EventArgs e)
            {
                string strAccountNumber = mtbAccountNumber.Text.Replace("-", "").Trim();
    
                if (string.IsNullOrEmpty(strAccountNumber))
                {
                    MsgBox.Regular("You should first type a valid customer account number, " +
                                   "and then click the Find Customer Account button.");
                    return;
                }
    
                StellarContext db = new();
                List<Customer> clients = new();
    
                clients = db.Customers!.ToList();
                Customer? client = clients.Find(cl => cl.AccountNumber == mtbAccountNumber.Text);
    
                txtAccountName.Text = client!.AccountName;
                string? 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;
    
                List<WaterMeter> meters = new();
    
                meters = db.WaterMeters!.ToList();
                WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == strMeterNumber);
    
                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)
                {
                    MessageBox.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)
                {
                    MessageBox.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 btnUpdateWaterBill_Click(object sender, EventArgs e)
            {
                // Make sure the user typed a (valid) bill number
                if (string.IsNullOrEmpty(txtBillNumber.Text))
                {
                    MsgBox.Regular("You must type a (unique) bill number for the " +
                                    "water bill you are processing.");
                    return;
                }
    
                // Make sure the user provided a customer's account number
                string strAccountNumber = mtbAccountNumber.Text.Replace("-", "").Trim();
    
                if (string.IsNullOrEmpty(strAccountNumber))
                {
                    MsgBox.Regular("You should first type a valid customer account number, " +
                                "and then click the Find Customer Account button.");
                    return;
                }
    
                // Get the value that the user typed. Consider it an integer
                int billNbr = int.Parse(txtBillNumber.Text);
    
                StellarContext db = new();
                List<WaterBill> bills = db.WaterBills!.ToList();
                /* Using the list of water bills, find a water bill 
                 * whose number is the same as the number the user typed. */
                WaterBill? bill = bills.Find(bl => bl.BillNumber == billNbr);
    
                // Check whether the user provided a valid bill number
                if (bill is null)
                {
                    MsgBox.Regular("There is no water bill with the bill number you typed.");
                    // If the provided bill number did not lead to a valid water bill, don't do anything
                    return;
                }
    
                /* Since the water bill was found, if the user changed 
                 * its values, update each value of water bille*/
                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);
    
                /* If/Since one or more values of the water bill 
                 * had been changed, save the updated water bill. */
                db.SaveChanges();
    
                // Return to the WaterBills.Central form to display an updated list of water bills
                Close();
            }
    
            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 Other Properties
    ListView List View lvwWaterBills   No Change
    Button Button btnNewWaterBill   No Change
    Button Button btnViewWaterBill   No Change
    Button Button btnEditWaterBill &Edit Water Bill... FlatStyle: Flat
    Anchor: Bottom, Right
  23. Double-click the Edit Water Bill button
  24. 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();
            }
    
            private void btnViewWaterBill_Click(object sender, EventArgs e)
            {
                Details details = new();
    
                details.Show();
            }
    
            private void btnEditWaterBill_Click(object sender, EventArgs e)
            {
                
            }
        }
    }
  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 Customers 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 - New Water Bill

  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

For any reason that is judged valuable, it may become desirable or necessary to cancel a water bill. We will create a form that can be used to delete a water bill.

Practical LearningPractical Learning: Editing/Updating a 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 FlatStyle: Flat
    &Delete Water Bill
  7. On the form, double-click the Find Water Bill button
  8. Change the document as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.WaterBills
    {
        public partial class Delete : Form
        {
            public Delete()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterBill_Click(object sender, EventArgs e)
            {
                if (string.IsNullOrEmpty(txtBillNumber.Text))
                {
                    // If the Bill Number text box is empty, ...
                    MsgBox.Regular("You must type a (valid) water bill number, " +
                                   "and then click the Find Water Bill button.");
                    // There is nothing to do. So, stop!
                    return;
                }
    
                /* Use Exception Handling in anticipation of bad occurrences.
                 * Check the "catch" sections. */
                try
                {
                    // Get a reference to the database context
                    StellarContext db = new();
    
                    // Get the value that the user typed. Consider it an integer
                    int billNbr = int.Parse(txtBillNumber.Text);
    
                    /* Get a list of water bills, convert it to a List<> object, 
                     * and store it in a List<> variable named bills. */
                    List<WaterBill> bills = db.WaterBills!.ToList();
    
                    try
                    {
                        /* Using the list of water bills, find a water bill 
                         * whose number is the same as the number the user typed. */
                        WaterBill? bill = bills.Find(bl => bl.BillNumber == billNbr);
    
                        // If a water bill was found, get its values and display them in the text boxes on the form.
                        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();
                        txtAmountDue.Text = bill.AmountDue.ToString();
                        txtPaymentDueDate.Text = bill.PaymentDueDate.ToLongDateString();
                        txtLateAmountDue.Text = bill.LateAmountDue.ToString();
                        txtLatePaymentDueDate.Text = bill.LatePaymentDueDate.ToLongDateString();
    
                        // Get the details of the customer who bill this is, and display them in the text boxes
                        List<Customer> clients = db.Customers!.ToList();
                        Customer? client = clients.Find(cl => cl.AccountNumber == txtAccountNumber.Text);
    
                        txtAccountName.Text = client!.AccountName;
                        string? 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;
    
                        // Get the details of the water meter that the cusomter is using, ...
                        List<WaterMeter> meters = db.WaterMeters!.ToList();
                        WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == strMeterNumber);
    
                        // and display those details in the Meter Details text box
                        txtMeterDetails.Text = meter!.Make + " " +
                                                        meter.Model +
                                                        " (Meter Size: " + meter.MeterSize + ")";
                    }
                    catch (NullReferenceException nre)
                    {
                        /* If the user typed some digits, find out whether that number corresponds to 
                         * a valid water bill number. If the number the user typed doesn't match 
                         * any bill number, then the application produced a NullReferenceException exception */
                        MsgBox.Regular("The number you typed doesn't match " +
                                       "any of the water bill numbers in our system." + Environment.NewLine +
                                       "The error produced was: " + nre.Message);
                    }
                }
                catch (FormatException fe)
                {
                    /* The bill number is an integer. If the user typed anything other  
                     *than digits, then the application produced a FormatException exception. */
                    MsgBox.Regular("You must type a valid water bill number." + Environment.NewLine +
                                   "The error produced was: " + fe.Message);
                }
                catch (Exception ex)
                {
                    MsgBox.Regular("Something went wrong trying to get water bill." + Environment.NewLine +
                                   "The error produced was: " + ex.Message);
                }
            }
        }
    }
  9. Return to the form and double-click the Delete Water Bill button
  10. Implement the event as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.WaterBills
    {
        public partial class Delete : Form
        {
            public Delete()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterBill_Click(object sender, EventArgs e)
            {
                . . .
            }
    
            private void btnDeleteWaterBill_Click(object sender, EventArgs e)
            {
                if (string.IsNullOrEmpty(txtBillNumber.Text))
                {
                    MsgBox.Regular("You must type the bill number of the water bill you " +
                                    "want to delete. Then click the Delete Water Bill button.");
                    return;
                }
    
                int billNbr = int.Parse(txtBillNumber.Text);
    
                StellarContext db = new();
                List<WaterBill> bills = db.WaterBills!.ToList();
                WaterBill? bill = bills.Find(bl => bl.BillNumber == billNbr);
    
                if (bill is null)
                {
                    MsgBox.Regular("There is no water bill with the bill number you typed.");
                    return;
                }
    
                string strQuestion = "Are you sure you want to delete this " +
                                     "water bill (the operation cannot be undone)?";
                
                if (MsgBox.Question(strQuestion) == DialogResult.Yes)
                {
                    db.WaterBills!.Remove(bill);
                    db.SaveChanges();
                }
    
                Close();
            }
        }
    }
  11. Return to the form and double-click the Close button
  12. Change the document as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.WaterBills
    {
        public partial class Delete : Form
        {
            public Delete()
            {
                InitializeComponent();
            }
    
            private void btnFindWaterBill_Click(object sender, EventArgs e)
            {
                /* Before doing anything, first find out whether the user entered 
                 * some value in the bill number text box. */
                if (string.IsNullOrEmpty(txtBillNumber.Text))
                {
                    // If the Bill Number text box is empty, ...
                    MsgBox.Regular("You must type a (valid) water bill number, " +
                                   "and then click the Find Water Bill button.");
                    // There is nothing to do. So, stop!
                    return;
                }
    
                /* Use Exception Handling in anticipation of bad occurrences.
                 * Check the "catch" sections. */
                try
                {
                    // Get a reference to the database context
                    StellarContext db = new();
    
                    // Get the value that the user typed. Consider it an integer
                    int billNbr = int.Parse(txtBillNumber.Text);
    
                    /* Get a list of water bills, convert it to a List<> object, 
                     * and store it in a List<> variable named bills. */
                    List<WaterBill> bills = db.WaterBills!.ToList();
    
                    try
                    {
                        /* Using the list of water bills, find a water bill 
                         * whose number is the same as the number the user typed. */
                        WaterBill? bill = bills.Find(bl => bl.BillNumber == billNbr);
    
                        // If a water bill was found, get its values and display them in the text boxes on the form.
                        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();
                        txtAmountDue.Text = bill.AmountDue.ToString();
                        txtPaymentDueDate.Text = bill.PaymentDueDate.ToLongDateString();
                        txtLateAmountDue.Text = bill.LateAmountDue.ToString();
                        txtLatePaymentDueDate.Text = bill.LatePaymentDueDate.ToLongDateString();
    
                        // Get the details of the customer who bill this is, and display them in the text boxes
                        List<Customer> clients = db.Customers!.ToList();
                        Customer? client = clients.Find(cl => cl.AccountNumber == txtAccountNumber.Text);
    
                        txtAccountName.Text = client!.AccountName;
                        string? 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;
    
                        // Get the details of the water meter that the cusomter is using, ...
                        List<WaterMeter> meters = db.WaterMeters!.ToList();
                        WaterMeter? meter = meters.Find(mtr => mtr.MeterNumber == strMeterNumber);
    
                        // and display those details in the Meter Details text box
                        txtMeterDetails.Text = meter!.Make + " " +
                                                        meter.Model +
                                                        " (Meter Size: " + meter.MeterSize + ")";
                    }
                    catch (NullReferenceException nre)
                    {
                        /* If the user typed some digits, find out whether that number corresponds to 
                         * a valid water bill number. If the number the user typed doesn't match 
                         * any bill number, then the application produced a NullReferenceException exception */
                        MsgBox.Regular("The number you typed doesn't match " +
                                       "any of the water bill numbers in our system." + Environment.NewLine +
                                       "The error produced was: " + nre.Message);
                    }
                }
                catch (FormatException fe)
                {
                    /* The bill number is an integer. If the user typed anything other  
                     *than digits, then the application produced a FormatException exception. */
                    MsgBox.Regular("You must type a valid water bill number." + Environment.NewLine +
                                   "The error produced was: " + fe.Message);
                }
                catch (Exception ex)
                {
                    MsgBox.Regular("Something went wrong trying to get water bill." + Environment.NewLine +
                                   "The error produced was: " + ex.Message);
                }
            }
    
            private void btnDeleteWaterBill_Click(object sender, EventArgs e)
            {
                // Make sure the user typed a (valid) bill number
                if (string.IsNullOrEmpty(txtBillNumber.Text))
                {
                    MsgBox.Regular("You must type the bill number of the water bill you " +
                                    "want to delete. Then click the Delete Water Bill button.");
                    return;
                }
    
                // Get the value that the user typed. Consider it an integer
                int billNbr = int.Parse(txtBillNumber.Text);
    
                StellarContext db = new();
                List<WaterBill> bills = db.WaterBills!.ToList();
                /* Using the list of water bills, find a water bill 
                 * whose number is the same as the number the user typed. */
                WaterBill? bill = bills.Find(bl => bl.BillNumber == billNbr);
    
                // Check whether the user provided a valid bill number
                if (bill is null)
                {
                    MsgBox.Regular("There is no water bill with the bill number you typed.");
                    // If the provided bill number did not lead to a valid water bill, don't do anything.
                    return;
                }
    
                string strQuestion = "Are you sure you want to delete this " +
                                     "water bill (the operation cannot be undone)?";
    
                // If the user really wants to delete the water bill, ...
                if (MsgBox.Question(strQuestion) == DialogResult.Yes)
                {
                    //... then delete that water bill
                    db.WaterBills!.Remove(bill);
                    // Now that the table has changed, save it
                    db.SaveChanges();
                }
    
                // Return to the WaterBills.Central form to display an updated list of water bills
                Close();
            }
    
            private void btnClose_Click(object sender, EventArgs e)
            {
                Close();
            }
        }
    }
  13. In the Solution Explorer, below the WaterBills folder, double-click Central.cs to open its form
  14. From the Toolbox, add two buttons to the form below the list view and to the right of the Edit Water Bill button
  15. 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... FlatStyle: Flat
    Anchor: Bottom, Right
    Button Button btnViewWaterBill &View Water Bill... FlatStyle: Flat
    Anchor: Bottom, Right
    Button Button btnEditWaterBill &Edit Water Bill... FlatStyle: Flat
    Anchor: Bottom, Right
    Button Button btnDeleteWaterBill &Delete Water Bill... FlatStyle: Flat
    Anchor: Bottom, Right
    Button Button btnClose &Close FlatStyle: Flat
    Anchor: Bottom, Right
  16. On the form, double-click the Delete Water Bill button
  17. Return to the Water Bills - Central form and double-click the Close button
  18. Implement the events as follows:
    using StellarWaterPoint53.Models;
    
    namespace StellarWaterPoint53.WaterBills
    {
        public partial class Central : Form
        {
            public Central()
            {
                InitializeComponent();
            }
    
            private void ShowWaterBills()
            {
                // Get a reference to the database context
                StellarContext db = new();
                // Get the customers records and store them in a List<> list named clients
                List<Customer> clients = [.. db.Customers!];
                // Get the water bills and store them in a List<> list named bills
                List<WaterBill> bills  = [.. db.WaterBills!];
    
                /* If you are planning to display the water bills records in 
                 * the list view, first remove everything from that list view.*/
                lvwWaterBills.Items.Clear();
    
                // Visit each record from the list of water bills
                foreach (WaterBill bill in bills)
                {
                    // Access the WaterBillId value and store it in the first column
                    ListViewItem lviWaterBill = new ListViewItem(bill.WaterBillId.ToString());
                    // Display the bill number in the second column
                    lviWaterBill.SubItems.Add(bill.BillNumber.ToString());
    
                    // Find the customer whose water bill is being accessed
                    Customer? client = clients.Find(cl => cl.AccountNumber == bill.AccountNumber);
    
                    /* We will display a short summary of the customer account.
                     * We will display the account number, the account name, the account type, 
                     * and the meter number of water meter associated with the account. */
                    lviWaterBill.SubItems.Add(bill.AccountNumber + " - " +
                                              client!.AccountName +
                                              ", Type: " + client.AccountType![..3] +
                                              ", (Mtr #: " + client.MeterNumber + ")");
    
                    /* Because a water bill contains many pieces of information, in the list view, 
                     * we will display only some information such as the meter reading start date, 
                     * the meter reading end date, the number of days included in the bill,
                     * the counter reading start number, the counter reading end number,
                     * the total HCF value, the total number of gallons consumed, 
                     * the payment due date, and the amount due. */
                    lviWaterBill.SubItems.Add(bill.MeterReadingStartDate.ToShortDateString());
                    lviWaterBill.SubItems.Add(bill.MeterReadingEndDate.ToShortDateString());
                    lviWaterBill.SubItems.Add(bill.BillingDays.ToString());
                    lviWaterBill.SubItems.Add(bill.CounterReadingStart.ToString());
                    lviWaterBill.SubItems.Add(bill.CounterReadingEnd.ToString());
                    lviWaterBill.SubItems.Add(bill.TotalHCF.ToString());
                    lviWaterBill.SubItems.Add(bill.TotalGallons.ToString());
                    lviWaterBill.SubItems.Add(bill.PaymentDueDate.ToShortDateString());
                    lviWaterBill.SubItems.Add(bill.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 btnViewWaterBill_Click(object sender, EventArgs e)
            {
                Details details = new Details();
    
                details.Show();
            }
    
            private void btnEditWaterBill_Click(object sender, EventArgs e)
            {
                Editor editor = new Editor();
    
                editor.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();
            }
        }
    }
  19. To execute, on the main menu, click Debug -> Start Without Debugging:

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

    Stellar Water Point - Water Bills

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

    Stellar Water Point - Water Bill Deletion

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

    Stellar Water Point - Water Bill Deletion

  23. Click Find Water Bill

    Stellar Water Point - Water Bill Deletion

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

    Stellar Water Point - Water Bills

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

Home Copyright © 2003-2025, FunctionX Tuesday 20 May 2025, 07:36