C# in Action - Part II: Building a GUI
- Inside the InvestmentForm Class
- The btnOK_Click() Method
- Summary
These days, most new applications are built with a graphical user interface (GUI). Programs using just the console are very few and far between—unless, of course, someone is creating instructional materials where simplicity is the rule. The example in this article builds upon Part I in this series by transforming the Investment Info program into a GUI application using Windows Forms.
The Investment Info program in this article is even easier than the console-based one. Just fill in the boxes and click the OK button. Click here for the entire listing.
The architecture of the Investment Info program has changed a bit. The presentation layer is now a Windows form, and it uses inheritance to obtain much of its functionality. The InvestmentController class has the exact same logic as in Part I, and it is used in a similar manner. This article will concentrate on the presentation layer, the InvestmentForm class.
Inside the InvestmentForm Class
Here's the class definition of the InvestmentForm:
public class InvestmentForm : System.Windows.Forms.Form { // . . . }
This declaration states that the InvestmentForm inherits the Windows Forms Form class. This means that the InvestmentForm class is now a form and can add whatever new functionality it needs to make it unique. Because the Form class has a title bar; Minimize, Maximize, and Close buttons; and a 3D surface, so does the InvestmentForm. Additionally, the InvestmentForm class has controls such as buttons, labels, and text boxes that specialize its appearance.
Each control is declared, similar to any other object. Controls are customized by setting various properties associated with each control type. Here's an example of customizing a label control:
private void InitializeComponent() { . . . // // lblInterest // this.lblInterest.Location = new System.Drawing.Point(56, 72); this.lblInterest.Name = "lblInterest"; this.lblInterest.Size = new System.Drawing.Size(56, 23); this.lblInterest.TabIndex = 1; this.lblInterest.Text = "Interest:"; this.lblInterest.TextAlign = System.Drawing.ContentAlignment.MiddleRight; . . .
The label shown is configured inside the InitializeComponent() method. This method is created by the Visual Studio.NET IDE when building a Windows Forms GUI. Unless you intend to maintain this code by hand in the future, you really shouldn't manually change any of these settings; let the GUI do it automatically. Most of the items in this label are easy to understand, but I'll elaborate a bit for clarification.
The Location property specifies the x and y coordinates of the upper-left corner of this control relative to the client area of the main form. The Size property specifies the width and height of this control. A TabIndex property identifies the sequence of controls that receive focus when the tab key is pressed. The TextAlign property accepts a ContentAlignment enum value.
An enum is another C# type that holds a collection of related ordinal values. For example, the ContentAlignment enum contains nine values: BottomCenter, BottomLeft, BottomRight, MiddleCenter, MiddleLeft, MiddleRight, TopCenter, TopLeft, and TopRight. Underlying enum values correspond to integral values, but they are strongly typed, meaning that they must be cast to an integral value if that's the way you want to use them.
A text box is configured similar to a label, as shown here:
// // txtPrincipal // this.txtPrincipal.Location = new System.Drawing.Point(152, 24); this.txtPrincipal.Name = "txtPrincipal"; this.txtPrincipal.TabIndex = 3; this.txtPrincipal.Text = ""; this.txtPrincipal.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
Buttons need to perform an action when they're clicked. This code shows how they can be configured:
// // btnOK // this.btnOK.Location = new System.Drawing.Point(109, 168); this.btnOK.Name = "btnOK"; this.btnOK.TabIndex = 6; this.btnOK.Text = "OK"; this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
Windows Forms controls have members that are C# event types. A program can register methods for control events, and, when the event is invoked, that method will be called. In the previous example, the button control has a Click event that is invoked any time the OK button is pressed.
Registering for an event requires that a delegate be added to the event with the compound addition operator (+=). A delegate is another C# reference type that enables runtime binding to methods. The delegate in the previous example is EventHandler and has the following signature:
Public delegate void EventHandler( Object sender, EventArgs e, );
This is the standard pattern for delegates supporting events. The Object sender parameter is the object sending the event, and the EventArgs e parameter contains data particular to that event. For a method to be assigned to a delegate, it must conform to the delegate signature. Therefore, the btnOK_Click() method has two parameters that are Object and EventArgs types and that returns void. I'll continue with the btnOK_Click() method in a little bit. Meanwhile, we'll finish the discussion of how to set up the form with the following code:
this.Controls.AddRange(new System.Windows.Forms.Control[] { this.btnOK, this.txtMonths, this.txtInterest, this.txtPrincipal, this.lblMonths, this.lblInterest, this.lblPrincipal});
The Controls collection is a member of the base class System.Windows.Forms.Form, which contains all the child controls belonging to the form. All the controls configured in the InterestForm must be added to this collection. Each of the controls could be added individually with the Add() method of the Controls collection. However, this example uses the AddRange() method, which accepts an array and adds all the controls at the same time. Figure 1 shows what the Investment Calculator program looks like.
Figure 1 The Investment Calculator program.