SDI and MDI Applications
SDI and MDI Applications
SDI and MDI Fundamentals
Introduction
A single-document interface, SDI, is an application primarily made of a form equipped with a menu. An example is Notepad:
In some cases, an SDI can also have a toolbar and/or a status bar. Here is an example from Microsoft Works Spreadsheet:
All these features are left to the programmer to add and configure.
Although Notepad is text-based, an SDI can be any type of application: text, graphics, spreadsheet, anything. Therefore, to create an SDI, start from a normal form, add a menu to it, and configure it to do what you want.
To create a document using an SDI, the user launches the application. The SDI then presents a rectangular window with one frame and the inside is the document the user will use. In most cases, the application itself creates the document. The user can work on it and do whatever the application allows. To create another document of the same type, the user must open another instance of the application.
Practical Learning: Introducing MDI Applications
namespace StellarWaterPoint1.Models { internal readonly record struct WaterMeter { public readonly string? MeterNumber { get; init; } public readonly string? Make { get; init; } public readonly string? Model { get; init; } public readonly string? MeterSize { get; init; } } }
namespace StellarWaterPoint1.Models { internal readonly record struct Customer { public readonly string? AccountNumber { get; init; } public readonly string? MeterNumber { get; init; } public readonly string? FirstName { get; init; } public readonly string? LastName { get; init; } public readonly string? Address { get; init; } public readonly string? City { get; init; } public readonly string? County { get; init; } public readonly string? State { get; init; } public readonly string? ZIPCode { get; init; } } }
namespace StellarWaterPoint1.Models { internal readonly record struct WaterBill { public readonly int BillNumber { get; init; } public readonly string? AccountNumber { get; init; } public readonly string? MeterReadingStartDate { get; init; } public readonly string? MeterReadingEndDate { get; init; } public readonly int BillingDays { get; init; } public readonly double CounterReadingStart { get; init; } public readonly double CounterReadingEnd { get; init; } public readonly double TotalGallons { get; init; } public readonly double TotalCCF { get; init; } public readonly double FirstTierConsumption { get; init; } public readonly double SecondTierConsumption { get; init; } public readonly double LastTierConsumption { get; init; } public readonly double WaterCharges { get; init; } public readonly double SewerCharges { get; init; } public readonly double EnvironmentCharges { get; init; } public readonly double TotalCharges { get; init; } public readonly double LocalTaxes { get; init; } public readonly double StateTaxes { get; init; } public readonly double AmountDue { get; init; } public readonly string? PaymentDueDate { get; init; } public readonly double LateAmountDue { get; init; } public readonly string? LatePaymentDueDate { get; init; } } }
namespace StellarWaterPoint1.Models { sealed internal class Repository { public static Customer[] Customers { get; set; } public static WaterBill[] WaterBills { get; set; } public static WaterMeter[] WaterMeters { get; set; } static Repository() { Customers = new Customer[10]; WaterBills = new WaterBill[10]; WaterMeters = new WaterMeter[10]; } public static void Add(in object addition) { if (addition is WaterMeter meter) { for (int i = 0; i < WaterMeters.Length; i++) { if (string.IsNullOrEmpty(WaterMeters[i].MeterNumber)) { WaterMeters[i] = new WaterMeter() { MeterNumber = meter.MeterNumber, Make = meter.Make, Model = meter.Model, MeterSize = meter.MeterSize }; break; } } } else if (addition is Customer client) { for (int i = 0; i < Customers.Length; i++) { if (string.IsNullOrEmpty(Customers[i].AccountNumber)) { Customers[i] = new Customer() { AccountNumber = client.AccountNumber, MeterNumber = client.MeterNumber, FirstName = client.FirstName, LastName = client.LastName, Address = client.Address, City = client.City, County = client.County, State = client.State, ZIPCode = client.ZIPCode, }; break; } } } else if (addition is WaterBill pay) { for (int i = 0; i < WaterBills.Length; i++) { if (WaterBills[i].BillNumber == 0) { WaterBills[i] = new WaterBill() { BillNumber = pay.BillNumber, AccountNumber = pay.AccountNumber, MeterReadingStartDate = pay.MeterReadingStartDate, MeterReadingEndDate = pay.MeterReadingEndDate, BillingDays = pay.BillingDays, CounterReadingStart = pay.CounterReadingStart, CounterReadingEnd = pay.CounterReadingEnd, TotalGallons = pay.TotalGallons, TotalCCF = pay.TotalCCF, FirstTierConsumption = pay.FirstTierConsumption, SecondTierConsumption = pay.SecondTierConsumption, LastTierConsumption = pay.LastTierConsumption, WaterCharges = pay.WaterCharges, SewerCharges = pay.SewerCharges, EnvironmentCharges = pay.EnvironmentCharges, TotalCharges = pay.TotalCharges, LocalTaxes = pay.LocalTaxes, StateTaxes = pay.StateTaxes, AmountDue = pay.AmountDue, PaymentDueDate = pay.PaymentDueDate, LateAmountDue = pay.LateAmountDue, LatePaymentDueDate = pay.LatePaymentDueDate }; break; } } } } public static WaterMeter GetWaterMeter(in string number) { if (number is not null) { for (int i = 0; i < WaterMeters.Length; i++) { if (WaterMeters[i].MeterNumber!.Equals(number)) { return WaterMeters[i]; } } } return new WaterMeter(); } public static Customer GetCustomer(in string number) { if (number is null) return new Customer(); for (int i = 0; i < Customers.Length; i++) { if (Customers[i].AccountNumber!.Equals(number)) { return Customers[i]; } } return new Customer(); } public static WaterBill GetWaterBill(in int number) { if (number == 0) return new WaterBill(); for (int i = 0; i < WaterBills.Length; i++) { if (WaterBills[i].BillNumber == number) { return WaterBills[i]; } } return new WaterBill(); } } }
MDI Fundamentals
A multiple-document interface, MDI, is an application that primarily has a form and a menu. Some, if not most, MDIs also have one or more toolbars and/or a status bar. Here is an example:
Like a normal application, to use an MDI, the user must launch it. In some cases, when the application starts, it is empty; that is, no document is created and the title bar displays a caption, usually the name of the application. Usually, there are steps the user must follow to create a document. In some other cases, when the application is launched, it automatically creates a document. A document resides inside the parent frame of the application. That is, a child document can use only the area reserved for it. The child document has its own system icon, its own title bar, and its own system buttons (Minimize, Maximize/Restore, and Close).
To use the whole area, the user can maximize the child document. When this is done, the child merges its title bar with the parent's. The new caption of the title bar becomes made of the text of the parent, followed by -, and followed by the caption the child window was using. The system buttons of the child document display under those of the parent frame:
Once a document has been created, the user can use it. Normally, the application must give the user the ability to create other documents while still using the application. If many documents have been created, all of them are confined to the frame of the parent:
The user can maximize the child forms. If so, the document that was in front occupies the whole area devoted to child documents. The other child forms stay in the back but become invisible.
One of the differences between an SDI and an MDI is that, because the child document and the MDI application don't share a frame, the user can close the child document and keep the application open.
Creating an MDI Application
As mentioned already, there is nothing magical with creating an SDI application. You start with a form, add a menu to it, and specify what the application should allow a user to do with a document. As we will see, an MDI requires more steps.
You start an MDI application with a normal form. You can create a Windows Forms Application using Microsoft Visual Studio or derive a class from Form. Here is an example:
using System.Windows.Forms; public class CommonParent : Form { public CommonParent() { InitializeComponent(); } void InitializeComponent() { } [STAThread] public static int Main() { Application.Run(new CommonParent()); return 0; } }
The primary form of an MDI application is referred to as the parent or MDI container. It provides the frame inside of which the documents will reside. To provide this functionality, the Form class is equipped with a Boolean property named IsMdiContainer. Therefore, after creating the first form of your application, to indicate that it acts as the main frame, set this property to true. You can do this in the Properties window if you are visually creating your application, or programmatically. Here is an example:
using System.Windows.Forms; public class CommonParent : Form { public CommonParent() { InitializeComponent(); } void InitializeComponent() { this.IsMdiContainer = true; } [STAThread] public static int Main() { Application.Run(new CommonParent()); return 0; } }
This would produce:
The primary characteristic of an MDI is that it contains other forms. These forms must be created and made available to the parent. Each form can be created using a predefined form or you can programmatically create one by declaring an object of type Form. To allow you to specify that a form has a parent and will act as a child, the Form class is equipped with a property named MdiParent. This is a read-write property. The set accessor indicates what form acts as this one's parent. To provide this information, assign the main form this form's MdiParent. After doing this, you can display the form when you are ready, by calling its Show() method. Here is an example:
using System.Windows.Forms;
public class CommonParent : Form
{
public CommonParent()
{
InitializeComponent();
}
void InitializeComponent()
{
this.IsMdiContainer = true;
Form frmChild = new Form();
frmChild.MdiParent = this;
frmChild.Show();
}
[STAThread]
public static int Main()
{
Application.Run(new CommonParent());
return 0;
}
}
This would produce:
Practical Learning: Creating an MDI Application
Control | (Name) | Text | Other Properties | |
Label | &Meter #: | |||
MaskedTextBox | mtbMeterNumber | Masked: 000-00-000 | ||
Label | M&ake: | |||
TextBox | txtMake | |||
Label | M&odel: | |||
TextBox | txtModel | Modifiers: Public | ||
Label | Me&ter Size: | |||
TextBox | txtMeterSize | |||
Button | btnSaveWateMeter | S&ave Water Meter |
(Name) | Text | Width |
colWaterMeterId | Id | 40 |
colMeterNumber | Meter # | 150 |
colMake | Make | 225 |
colModel | Model | 100 |
colMeterSize | Meter Size | 150 |
Control | (Name) | Other Properties | |
ListView | lvwWaterMeters | FullRowSelect: True GridLines: True View: Details Anchor: Top, Bottom, Left, Right |
Control | (Name) | Text | Mask | |
Label | &Account #: | |||
MaskedTextBox | mtbAccountNumber | Masked: 0000-000-0000 | ||
Label | &Meter #: | |||
MaskedTextBox | mtbMeterNumber | Masked: 000-00-000 | ||
Button | btnFindWaterMeter | &Find Water Meter | ||
Label | Meter &Details: | |||
TextBox | txtMeterDetails | |||
Label | &First Name: | |||
TextBox | txtFirstName | |||
Label | &Last Name: | |||
TextBox | txtLastName | |||
Label | &Address: | |||
TextBox | txtAddress | |||
Label | C&ity: | |||
TextBox | txtCity | |||
Label | C&ounty: | |||
TextBox | txtCounty | |||
Label | &State: | |||
TextBox | txtState | |||
Label | &ZIP-Code: | |||
MaskedTextBox | mtbZIPCode | Masked: Zip-Code | ||
Button | btnSaveCustomerAccount | S&ave Customer Account |
(Name) | Text | TextAlign | Width |
colCustomerId | Id | 40 | |
colAccountNumber | Account # | Center | 175 |
colMeterNumber | Meter # | Center | 150 |
colFirstName | First Name | 125 | |
colLastName | Last Name | 125 | |
colAddress | Address | 250 | |
colCity | City | 125 | |
colCounty | County | 150 | |
colState | State | Center | |
colZIPCode | ZIP-Code | Center | 125 |
Control | (Name) | Other Properties | |
ListView | lvwCustomers | FullRowSelect: True GridLines: True View: Details Anchor: Top, Bottom, Left, Right |
Control | (Name) | Text | Other Properties | |
Label | Water Bill #: | |||
TextBox | txtBillNumber | |||
GroupBox | Customer Information | |||
Label | Account #: | |||
MaskedTextBox | mtbAccountNumber | Masked: 0000-000-0000 | ||
Button | btnFindCustomerAccount | Find Customer Account | ||
Label | Customer Name: | |||
TextBox | txtCustomerName | |||
Label | Address: | |||
TextBox | txtAddress | |||
TextBox | txtCity | |||
TextBox | txtCounty | |||
TextBox | txtState | |||
MaskedTextBox | mtbZIPCode | Masked: Zip-Code | ||
Label | _______________________ | |||
Label | Meter Details: | |||
TextBox | txtMeterDetails | Modifiers: Public | ||
GroupBox | Meter Reading | |||
Label | Meter Reading Start Date: | |||
MaskedTextBox | mtbMeterReadingStartDate | Masked: Short Date | ||
Label | Meter Reading End Date: | |||
MaskedTextBox | mtbMeterReadingEndDate | Masked: Short Date | ||
Label | Counter Reading Start: | |||
TextBox | txtCounterReadingStart | |||
Label | Counter Reading End: | |||
TextBox | txtCounterReadingEnd | |||
Button | btnEvaluateWaterBill | Evaluate Water Bill | ||
GroupBox | Meter Result | |||
Label | Billing Days: | |||
TextBox | txtBillingDays | TextAlign: Right | ||
Label | Total Gallons: | |||
TextBox | txtTotalGallons | TextAlign: Right | ||
Label | Total CCF: | |||
TextBox | txtTotalCCF | TextAlign: Right | ||
Label | First Tier Consumption: | |||
TextBox | txtFirstTierConsumption | TextAlign: Right | ||
Label | Second Tier: | |||
TextBox | txtSecondTierConsumption | TextAlign: Right | ||
Label | Last Tier: | |||
TextBox | txtLastTierConsumption | TextAlign: Right | ||
GroupBox | Consumption Charges | |||
Label | Water Charges: | |||
TextBox | txtWaterCharges | TextAlign: Right | ||
Label | Sewer Charges: | |||
TextBox | txtSewerCharges | TextAlign: Right | ||
Label | Environment Charges: | |||
TextBox | txtEnvironmentCharges | TextAlign: Right | ||
Label | Total Charges: | |||
TextBox | txtTotalCharges | TextAlign: Right | ||
GroupBox | Taxes | |||
Label | Local Taxes: | |||
TextBox | txtLocalTaxes | TextAlign: Right | ||
Label | State Taxes: | |||
TextBox | txtStateTaxes | TextAlign: Right | ||
GroupBox | Water Bill Payment | |||
Label | Payment Due Date: | |||
MaskedTextBox | mtbPaymentDueDate | Masked: Short Date | ||
Label | Amount Due: | |||
TextBox | txtAmountDue | TextAlign: Right | ||
Label | Late Payment Due Date: | |||
MaskedTextBox | mtbLatePaymentDueDate | Masked: Short Date | ||
Label | Late Amount Due: | |||
TextBox | txtLateAmountDue | TextAlign: Right | ||
Button | btnSaveWaterBill | Save Water Bill |
Control | (Name) | Text | |
Button | btnFindWaterBill | Find Water &Bill |
MDI Characteristics
Introduction to the Children of an MDI
When you create an MDI application, you must make sure you provide your users with the ability to create documents. In fact, probably one of your first assignments is to make sure the user can create as many documents as necessary. As the documents are created, you need a way to programmatically keep track of the child forms. For example, you can store the documents in a collection. To assist you with this, the Form class is equipped with a property named MdiChildren, which is a read-only array. Each element of the MdiChildren[] array is of type Form. Therefore, to access a child form of an MDI application, you can pass an index to this property.
The Layout of Child Forms
Based on the standards defined in the operating system, as child forms are created in an MDI application, they are positioned each on top of the previous one but below the next one. The arrangement uses a 3-D coordiniate system whose origin is on the lower-left corner of the parent's frame just under the title bar (or the menu, if any; or the toolbar, if any), with the Z axis moving from the monitor towards you:
The operating system allows the user to choose among different arrangements. For example, you can position the documents as vertical columns, as horizontal rows, or as tiles. To support this, the Form class is equipped with a method named LayoutMdi. Its syntax is:
public void LayoutMdi(MdiLayout value);
The LayoutMdi() method takes an argument that is a member of the MdiLayout enumeration. The members of this enumeration are Cascade, TileHorizontal, TileVertical, and ArrangeIcons.
Practical Learning: Laying Out the Documents
Text | (Name) |
&File | miFile |
Water &Bills | miWaterBills |
&Customers | miCustomers |
Water &Meters | miWaterMeters |
&Window | miWindow |
&Help | miHelp |
Text | (Name) | Shortcuts |
E&xit | miFileExit | Alt + F4 |
Text | (Name) | Shortcuts |
&Prepare Water Bill... | miWaterBillsCreate | Ctrl+Shift+B |
&View Water Bill... | miWaterBillsView | Ctrl+Shift+V |
Text | (Name) | Shortcuts |
&Create Customer Account... | miCustomersCreate | Ctrl+Shift+C |
&View All Accounts... | miCustomerViewAll | Ctrl+Shift+A |
Text | (Name) | Shortcuts |
&Setup Water Meter... | miWaterMetersCreate | Ctrl+Shift+W |
&View All Water Meters... | miWaterMeterViewAll | Ctrl+Shift+T |
Text | (Name) |
&Arrange | miWindowArrange |
&Cascade | miWindowCascade |
Tile &Horizontal | miWindowTileHorizontal |
Tile &Vertical | mnuWindowTileVertical |
Text | (Name) | Shortcuts |
&About Stellar Water Point... | miHelpAbout | Ctrl+F1 |
namespace StellarWaterPoint11 { public partial class WaterDistribution : Form { public static bool MetersDisplaying; public static bool CreateMeterDisplaying; public static bool ClientsDisplaying; public static bool CreateClientDisplaying; public static bool ViewBillDisplaying; public static bool CreateBillDisplaying; private WaterMeters.Create createMeter; private WaterMeters.Manage meters; private Customers.Create client; private Customers.ViewAll clients; private WaterBills.Create createBill; private WaterBills.Details billDetails; public WaterDistribution() { InitializeComponent(); MetersDisplaying = false; CreateMeterDisplaying = false; ClientsDisplaying = false; CreateClientDisplaying = false; ViewBillDisplaying = false; CreateBillDisplaying = false; createBill = new WaterBills.Create(); billDetails = new WaterBills.Details(); createMeter = new WaterMeters.Create(); meters = new WaterMeters.Manage(); client = new Customers.Create(); clients = new Customers.ViewAll(); } private void miWaterBillsCreate_Click(object sender, EventArgs e) { if (CreateBillDisplaying == false) { createBill = new(); createBill.MdiParent = this; createBill.Show(); CreateBillDisplaying = true; } else { createBill.BringToFront(); } } private void miWaterBillsView_Click(object sender, EventArgs e) { if (ViewBillDisplaying == false) { billDetails = new(); billDetails.MdiParent = this; billDetails.Show(); } else { billDetails.BringToFront(); } } private void miCustomersCreate_Click(object sender, EventArgs e) { if (CreateClientDisplaying == false) { client = new Customers.Create(); client.MdiParent = this; client.Show(); CreateClientDisplaying = true; } else { client.BringToFront(); } } private void miCustomerViewAll_Click(object sender, EventArgs e) { if (ClientsDisplaying == false) { clients = new(); clients.MdiParent = this; clients.Show(); ClientsDisplaying = true; } else { clients.BringToFront(); } } private void miWaterMetersCreate_Click(object sender, EventArgs e) { if (CreateMeterDisplaying == false) { createMeter = new(); createMeter.MdiParent = this; createMeter.Show(); CreateMeterDisplaying = true; } else { createMeter.BringToFront(); } } private void miWaterMeterViewAll_Click(object sender, EventArgs e) { if (MetersDisplaying == false) { meters = new WaterMeters.Manage(); meters.MdiParent = this; meters.Show(); MetersDisplaying = true; } else { meters.BringToFront(); } } private void miWindowArrange_Click(object sender, EventArgs e) { LayoutMdi(MdiLayout.ArrangeIcons); } private void miWindowCascade_Click(object sender, EventArgs e) { LayoutMdi(MdiLayout.Cascade); } private void miWindowTileHorizontal_Click(object sender, EventArgs e) { LayoutMdi(MdiLayout.TileHorizontal); } private void mnuWindowTileVertical_Click(object sender, EventArgs e) { LayoutMdi(MdiLayout.TileVertical); } private void miHelpAbout_Click(object sender, EventArgs e) { AboutSWP about = new AboutSWP(); about.ShowDialog(); } private void miFileExit_Click(object sender, EventArgs e) { Close(); } } }
using StellarWaterPoint1.Models; namespace StellarWaterPoint1.Customers { public partial class Create : Form { public Create() { InitializeComponent(); } private void btnFindWaterMeter_Click(object sender, EventArgs e) { if (string.IsNullOrEmpty(mtbMeterNumber.Text)) { MessageBox.Show("You must type the meter number associated with the customer's account.", "Stellar Water Point", MessageBoxButtons.OK); return; } WaterMeter meter = Repository.GetWaterMeter(mtbMeterNumber.Text); txtMeterDetails.Text = meter.Make + " " + meter.Model + " (Meter #: " + meter.MeterSize + ")"; } private void btnSaveCustomerAccount_Click(object sender, EventArgs e) { if (string.IsNullOrEmpty(mtbAccountNumber.Text)) { MessageBox.Show("You must type an account number for the new customer.", "Stellar Water Point", MessageBoxButtons.OK); return; } Customer account = new Customer() { AccountNumber = mtbAccountNumber.Text, MeterNumber = mtbMeterNumber.Text, FirstName = txtFirstName.Text, LastName = txtLastName.Text, Address = txtAddress.Text, City = txtCity.Text, County = txtCounty.Text, State = txtState.Text, ZIPCode = mtbZIPCode.Text }; Repository.Add(account); Close(); } private void Create_FormClosing(object sender, FormClosingEventArgs e) { if (WaterDistribution.CreateClientDisplaying == true) { WaterDistribution.CreateClientDisplaying = false; Close(); } } } }
using StellarWaterPoint1.Models; namespace StellarWaterPoint1.Customers { public partial class ViewAll : Form { public ViewAll() { InitializeComponent(); } private void ShowCustomers() { int counter = 1; lvwCustomers.Items.Clear(); foreach (Customer cust in Repository.Customers) { if (!(string.IsNullOrEmpty(cust.AccountNumber))) { ListViewItem lviCustomer = new ListViewItem(counter++.ToString()); lviCustomer.SubItems.Add(cust.AccountNumber); lviCustomer.SubItems.Add(cust.MeterNumber); lviCustomer.SubItems.Add(cust.FirstName); lviCustomer.SubItems.Add(cust.LastName); lviCustomer.SubItems.Add(cust.Address); lviCustomer.SubItems.Add(cust.City); lviCustomer.SubItems.Add(cust.County); lviCustomer.SubItems.Add(cust.State); lviCustomer.SubItems.Add(cust.ZIPCode); lvwCustomers.Items.Add(lviCustomer); } } } private void ViewAll_Activated(object sender, EventArgs e) { ShowCustomers(); } private void ViewAll_FormClosing(object sender, FormClosingEventArgs e) { if (WaterDistribution.ClientsDisplaying == true) { WaterDistribution.ClientsDisplaying = false; Close(); } } } }
using StellarWaterPoint1.Models; namespace StellarWaterPoint1.WaterMeters { public partial class Create : Form { public Create() { InitializeComponent(); } private void btnSaveWaterMeter_Click(object sender, EventArgs e) { if (string.IsNullOrEmpty(mtbMeterNumber.Text)) { MessageBox.Show("You must type the meter number. " + "Otherwise, the water meter cannot be set up.", "Stellar Water Point", MessageBoxButtons.OK); return; } WaterMeter wm = new WaterMeter() { MeterNumber = mtbMeterNumber.Text, Make = txtMake.Text, Model = txtModel.Text, MeterSize = txtMeterSize.Text }; Repository.Add(wm); Close(); } private void Create_FormClosing(object sender, FormClosingEventArgs e) { if (WaterDistribution.CreateMeterDisplaying == true) { WaterDistribution.CreateMeterDisplaying = false; Close(); } } } }
using StellarWaterPoint1.Models; namespace StellarWaterPoint1.WaterMeters { public partial class Manage : Form { public Manage() { InitializeComponent(); } void ShowWaterMeters() { int counter = 1; lvwWaterMeters.Items.Clear(); foreach (WaterMeter wm in Repository.WaterMeters) { if (!(string.IsNullOrEmpty(wm.MeterNumber))) { ListViewItem lviWaterMeter = new ListViewItem(counter++.ToString()); lviWaterMeter.SubItems.Add(wm.MeterNumber); lviWaterMeter.SubItems.Add(wm.Make); lviWaterMeter.SubItems.Add(wm.Model); lviWaterMeter.SubItems.Add(wm.MeterSize); lvwWaterMeters.Items.Add(lviWaterMeter); } } } private void Manage_Activated(object sender, EventArgs e) { ShowWaterMeters(); } private void Manage_FormClosing(object sender, FormClosingEventArgs e) { if (WaterDistribution.MetersDisplaying == true) { WaterDistribution.MetersDisplaying = false; Close(); } } } }
using StellarWaterPoint1.Models; namespace StellarWaterPoint1.WaterBills { public partial class Create : Form { public Create() { InitializeComponent(); } private void btnFindCustomerAccount_Click(object sender, EventArgs e) { if (string.IsNullOrEmpty(mtbAccountNumber.Text)) { MessageBox.Show("You must enter a bill number.", "Stellar Water Point", MessageBoxButtons.OK); return; } Customer client = Repository.GetCustomer(mtbAccountNumber.Text); string strMeterNumber = string.Empty; txtCustomerName.Text = client.FirstName + " " + client.LastName; strMeterNumber = client.MeterNumber!; txtAddress.Text = client.Address; txtCity.Text = client.City; txtCounty.Text = client.County; txtState.Text = client.State; txtZIPCode.Text = client.ZIPCode; WaterMeter meter = Repository.GetWaterMeter(strMeterNumber); txtMeterDetails.Text = meter.Make + " " + meter.Model + " (Meter #: " + meter.MeterSize + ")"; } private void btnEvaluateWaterBill_Click(object sender, EventArgs e) { double counterStart = 0, counterEnd = 0; try { counterStart = double.Parse(txtCounterReadingStart.Text); } catch (FormatException feCRStart) { MessageBox.Show("There was a problem with the value of the " + "Counter Reading Start. The error produced is: " + feCRStart.Message, "Stellar Water Point", MessageBoxButtons.OK, MessageBoxIcon.Information); } try { counterEnd = double.Parse(txtCounterReadingEnd.Text); } catch (FormatException feCREnd) { MessageBox.Show("There was a problem with the value of the " + "Counter Reading End. The error produced is: " + feCREnd.Message, "Stellar Water Point", MessageBoxButtons.OK, MessageBoxIcon.Information); } double consumption = counterEnd - counterStart; double gallons = consumption * 748.05; double firstTier = gallons * (48.00 / 10000.00); double secondTier = gallons * (32.00 / 10000.00); double lastTier = gallons * (20.00 / 10000.00); double waterCharges = firstTier + secondTier + lastTier; double sewerCharges = waterCharges * 28.65 / 100; double envCharges = waterCharges * 0.22184; double totalCharges = waterCharges + sewerCharges + envCharges; double localTaxes = totalCharges * 0.06148; double stateTaxes = totalCharges * 0.01374; double amtDue = totalCharges + localTaxes + stateTaxes; txtTotalCCF.Text = consumption.ToString(); txtTotalGallons.Text = gallons.ToString("F"); txtFirstTierConsumption.Text = firstTier.ToString("F"); txtSecondTierConsumption.Text = secondTier.ToString("F"); txtLastTierConsumption.Text = lastTier.ToString("F"); txtWaterCharges.Text = waterCharges.ToString("F"); txtSewerCharges.Text = sewerCharges.ToString("F"); txtEnvironmentCharges.Text = envCharges.ToString("F"); txtTotalCharges.Text = totalCharges.ToString("F"); txtLocalTaxes.Text = localTaxes.ToString("F"); txtStateTaxes.Text = stateTaxes.ToString("F"); txtAmountDue.Text = amtDue.ToString("F"); txtLateAmountDue.Text = (amtDue + 8.95).ToString("F"); } private void btnSaveWaterBill_Click(object sender, EventArgs e) { WaterBill bill = new WaterBill() { BillNumber = int.Parse(txtBillNumber.Text), AccountNumber = mtbAccountNumber.Text, MeterReadingStartDate = mtbMeterReadingStartDate.Text, MeterReadingEndDate = mtbMeterReadingEndDate.Text, BillingDays = int.Parse(txtBillingDays.Text), CounterReadingStart = double.Parse(txtCounterReadingStart.Text), CounterReadingEnd = double.Parse(txtCounterReadingEnd.Text), TotalGallons = double.Parse(txtTotalGallons.Text), TotalCCF = double.Parse(txtTotalCCF.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), TotalCharges = double.Parse(txtTotalCharges.Text), LocalTaxes = double.Parse(txtLocalTaxes.Text), StateTaxes = double.Parse(txtStateTaxes.Text), AmountDue = double.Parse(txtAmountDue.Text), PaymentDueDate = mtbPaymentDueDate.Text, LateAmountDue = double.Parse(txtLateAmountDue.Text), LatePaymentDueDate = mtbLatePaymentDueDate.Text }; Repository.Add(bill); Close(); } private void Create_FormClosing(object sender, FormClosingEventArgs e) { if (WaterDistribution.CreateBillDisplaying == true) { WaterDistribution.CreateBillDisplaying = false; Close(); } } } }
using StellarWaterPoint1.Models; namespace StellarWaterPoint1.WaterBills { public partial class Details : Form { public Details() { InitializeComponent(); } private void btnFindWaterBill_Click(object sender, EventArgs e) { if (string.IsNullOrEmpty(txtWaterBillNumber.Text)) { MessageBox.Show("You must type a water bill number.", "Stellar Water Point", MessageBoxButtons.OK); return; } WaterBill bill = Repository.GetWaterBill(int.Parse(txtWaterBillNumber.Text)); mtbAccountNumber.Text = bill.AccountNumber; mtbMeterReadingStartDate.Text = bill.MeterReadingStartDate; mtbMeterReadingEndDate.Text = bill.MeterReadingEndDate; txtBillingDays.Text = bill.BillingDays.ToString(); txtCounterReadingStart.Text = bill.CounterReadingStart.ToString(); txtCounterReadingEnd.Text = bill.CounterReadingEnd.ToString(); txtTotalGallons.Text = bill.TotalGallons.ToString(); txtTotalCCF.Text = bill.TotalCCF.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(); txtTotalCharges.Text = bill.TotalCharges.ToString(); txtLocalTaxes.Text = bill.LocalTaxes.ToString(); txtStateTaxes.Text = bill.StateTaxes.ToString(); txtAmountDue.Text = bill.AmountDue.ToString(); mtbPaymentDueDate.Text = bill.PaymentDueDate; txtLateAmountDue.Text = bill.LateAmountDue.ToString(); mtbLatePaymentDueDate.Text = bill.LatePaymentDueDate; string strMeterNumber = string.Empty; Customer client = Repository.GetCustomer(mtbAccountNumber.Text); strMeterNumber = client.MeterNumber!; txtCustomerName.Text = client.FirstName + " " + client.LastName; txtAddress.Text = client.Address; txtCity.Text = client.City; txtCounty.Text = client.County; txtState.Text = client.State; mtbZIPCode.Text = client.ZIPCode; WaterMeter meter = Repository.GetWaterMeter(strMeterNumber); txtMeterDetails.Text = meter.Make + " " + meter.Model + " (Meter #: " + meter.MeterSize + ")"; } private void Details_FormClosing(object sender, FormClosingEventArgs e) { if (WaterDistribution.ViewBillDisplaying == true) { WaterDistribution.ViewBillDisplaying = false; Close(); } } } }
Meter # | Make | Model | Meter Size |
392-44-572 | Constance Technologies | TG-4822 | 5/8 Inches |
938-75-869 | Stanford Trend | 266G | 1 1/2 Inches |
588-29-663 | Estellano | NCF-226 | 3/4 Inches |
186-92-805 | Lansome | 2800 | 1 1/2 Inches |
799-28-461 | Kensa Sons | K-584-L | 3/4 Inches |
386-48-057 | Estellano | NCF-226 | 3/4 Inches |
837-06-836 | Lansome | 7400 | 5/8 Inches |
207-94-835 | Constance Technologies | TG-6220 | 5/8 Inches |
592-84-957 | Kensa Sons | D-497-H | 3/4 Inches |
374-06-284 | Raynes Energica | i2022 | 3/4 Inches |
186-99-757 | Kensa Sons | M-686-G | 1 1/2 Inches |
630-07-055 | Lansome | 2800 | 3/4 Inches |
827-50-248 | Standard Trend | 428T | 3/4 Inches |
470-68-850 | Estellano | WRT-482 | 3/4 Inches |
649-33-505 | Constance Technologies | BD-7000 | 5/8 Inches |
306-82-497 | Lansome | 9000 | 3/4 Inches |
Account # | Meter # | First Name | Last Name | Address | City | County | State | ZIP-Code |
9279-570-8394 | 799-28-461 | Thomas | Stones | 10252 Broward Ave #D4 | Frederick | Frederick | MD | 21703-6628 |
2068-258-9486 | 186-92-805 | Ericka | Dellaney | 4819 East Munk Street | Whitehall | Fulton | PA | 17340-2277 |
4820-375-2842 | 392-44-572 | Akhil | Koumari | 748 Red Hills Rd | Roanoke | VA | 24012-9726 | |
6003-386-3955 | 374-06-284 | Mandiakandara | Marmoudi | 539 Avalon Court | Greenwood | Sussex | DE | 19950-2288 |
9249-379-6848 | 588-29-663 | Richard | Eghert | 8280 Sligo North Way | Albright | Preston | WV | 26519-4626 |
7518-302-6895 | 207-94-835 | Grace | Brenner | 4299 Peachtree Court | Rockville | Montgomery | MD | 20853-1512 |
3028-502-9418 | 186-99-757 | Spencer | Kershaw | 338C Grayson Street | Gatchellville | York | PA | 17352-3808 |
5293-957-3395 | 386-48-057 | Kelly | Davids | 10484 Greenway Avenue | Mt Storm | Grant | WV | 26739-6242 |
2038-413-9680 | 938-75-869 | Amidou | Gomah | 2075 Rose Hills Avenue | Washington | DC | 20004-1818 | |
7028-405-9381 | 306-82-497 | Jonathan | Simmings | 613 Meadowhill Road | Alonzaville | Shenandoah | VA | 22664-2662 |
5938-074-5293 | 592-84-957 | Marie | Rath | 582G Dunhill Avenue | Lanham | Prince Georges | MD | 20706-4422 |
1827-395-0203 | 470-68-850 | Sathyavanthara | Khooni | 10331 Chryswell Road | Washington | DC | 20008-5050 | |
8027-304-6829 | 837-06-836 | Anthony | Clarcksons | 904 Augusta Drive | Blackbird | New Castle | DE | 19734-2606 |
6699-396-2905 | 649-33-505 | Spencer | Reuter | 2850 Burnsweak Avenue | Silver Spring | Montgomery | MD | 20910-7272 |
7080-583-5947 | 827-50-248 | Sandra | Moffat | 663 Sherry Wood East Street | Shimpstown | Franklin | PA | 17236-1116 |
Water Bill #: 847384 Account #: 3028-502-9418 Meter Reading Start Date: 10/03/2022 Meter Reading End Date: 01/06/2023 Counter Reading Start: 16 Counter Reading End: 21 Billing Days: 95 Payment Due Date: 01/21/2023 Late Payment Due Date: 02/05/2023
Water Bill # | Account # | Meter Reading Start Date | Meter Reading End Date | Counter Reading Start | Counter Reading End | Billing Days | Payment Due Date | Late Payment Due Date |
330820 | 7028-405-9381 | 10/03/2022 | 01/03/2023 | 9749 | 9906 | 92 | 01/18/2023 | 02/02/2023 |
468550 | 7518-302-6895 | 10/05/2022 | 01/09/2023 | 96 | 114 | 96 | 01/24/2023 | 02/08/2023 |
148274 | 9249-379-6848 | 10/05/2022 | 01/10/2023 | 260504 | 260555 | 97 | 01/25/2023 | 02/09/2023 |
326384 | 2068-258-9486 | 10/08/2022 | 01/10/2023 | 104837 | 104851 | 94 | 01/25/2023 | 02/09/2023 |
Activating a Child
In most MDI applications, a user can create as many documents as necessary. This also means that the application can hold many child forms. To access a child form, the user can click its title bar. You can also provide options on a menu item named Window that would display a list of open documents.
When a child window is activated, it fires an event named MdiChildActivate:
public event EventHandler MdiChildActivate;
The MdiChildActivate event is of type EventArgs.
The document that is currently active has a brighter title bar. To identify this document, the form has a property named ActiveMdiChild. This read-only property allows you to know what document is the current active one. This property is of type Form, which means it produces a Form object. When you enquire about this property, if its value is null, it means there is no current active document. Here is an example of accessing the current active child document:
private void mnuFileClose_Click(object sender, EventArgs e) { SingleDocument document = (SingleDocument)ActiveMdiChild; if( document != null ) { document.Close(); } if (MdiChildren.Length== 0) mnuFileClose.Enabled = false; }
If the value of the ActiveMdiChild property is not null, a document is active and you can use it. If you want to access the objects (Windows controls) that are positioned on a child form, remember that the child form is somehow foreign. Therefore, you should set the Modifiers property of its hosted controls approppriately. For example, if you want the parent frame to access a control on the child frame, set the Modifiers of that control to Public.
Arranging the Minimized Children
In an MDI application, if the user doesn't want to display a document but doesn't want to close it, he or she can minimise the window. In the same way, the user can minimize as many child forms as necessary. When a child form has been minimized, it shows a button in the lower part of the parent. The buttons of the other minimized child forms are usually positioned next to each other:
The user can move the buttons at will:
A user can also close the child form using the Close button of its minimized button. At one time the minimized buttons may display as a "mess". To let you rearrange them, call the LayoutMdi() method of the Form class and pass the argument as ArrangeIcons. When you do this, the application will visit all buttons, if any, that represent minimized child documents, and position them from the left to the right, adjacently.
Microsoft Visual Studio Assistance With MDI Applications
Microsoft Visual Studio makes it easy for you to create an MDI application. It doesn't do everything for you but it provides all the primary design you may need. It does this through the MDI Parent Form of the Add New Item dialog box.
Practical Learning: Ending the Application
|
|||
Previous | Copyright © 2010-2024, FunctionX, Inc. | Friday 10 June 2022 | Next |
|