Windows Forms and Visual Studio .NET

Building applications by hand is a great way to learn the mechanics of Windows Forms, but in practice, most Windows Forms developers use Visual Studio .NET to craft their wares. Visual Studio .NET is the version of Visual Studio for .NET Framework developers. Its many features include an integrated editor, compiler, and debugger, context-sensitive help in the form of IntelliSense, and a built-in forms designer that simplifies the task of laying out and implementing Windows forms.

To acquaint you with Windows Forms development Visual Studio .NET–style, the remaining sections of this chapter provide step-by-step instructions for building a very practical Windows Forms application—a reverse Polish notation (RPN) calculator capable of performing addition, subtraction, multiplication, and division. Figure 4-23 shows the finished product.

Figure 4-23
The NetCalc application.

In case you’re not familiar with RPN calculators, here’s a brief tutorial. To add 2 and 2 on a conventional calculator, you press the following keys:

2
+
2
=

To add 2 and 2 on an RPN calculator, you do this instead:

2
Enter
2
+

The first two key presses—2 and Enter—push a 2 onto the calculator’s internal evaluation stack. Pressing 2 again pushes another 2 onto the stack and moves the other one up one slot. Pressing the plus key (+) pops both 2s off the stack, adds them together, and pushes the result onto the stack. A 4 appears in the calculator’s output window because the value at the top of the stack is always shown there.

One of the beauties of RPN calculators is that you don’t need parentheses, and even complex expressions can be evaluated with a minimum of effort. Suppose, for example, you were given the following expression:

((2?+?2)?*?6)?/?3

Evaluating this expression would be a chore on a conventional calculator (especially one that lacks parentheses), but not on an RPN calculator. Here’s the sequence of keystrokes:

2
Enter
2
+
6
*
3
/

RPN was popularized on Hewlett-Packard scientific calculators in the 1970s. Once you get used to crunching numbers the RPN way, you’ll never want to use a conventional calculator again. But enough about the virtues of RPN. Let’s write some code.

Step 1: Create a Project

The first step in creating a Windows Forms application in Visual Studio .NET is to create a project. To begin, choose the New/Project command from Visual Studio .NET’s File menu. When the New Project dialog appears, make sure Visual C# Projects is selected in the Project Types box, as shown in Figure 4-24. Then choose Windows Application to identify the kind of application you intend to create. Type “NetCalc” into the Name box to give the project a name, and then click the OK button.

Figure 4-24
Creating a C# Windows Forms project.
Step 2: Design the Form

After creating the project, Visual Studio .NET will drop you into its forms designer, which is a visual tool for adding controls to forms, setting properties on those controls, writing event handlers, and more. The forms designer initially displays a blank form.

The next order of business is to customize the title at the top of the form. The default is “Form1.” Change that by locating the form’s Text property in the Properties window (by default, the Properties window appears in the lower right corner of Visual Studio .NET’s main window) and changing “Form1” to “NetCalc.” The new title should appear in the form’s title bar in the forms designer. While you’re at it, make the form nonresizable by setting its Form-BorderStyle property to FixedDialog, and disable its maximize box by setting MaximizeBox to false. The following table summarizes the properties that need to be changed:

Property

Value

Text

“NetCalc”

FormBorderStyle

FixedDialog

MaximizeBox

False

On the left side of the Visual Studio .NET window is a vertical button labeled “Toolbox.” Moving the cursor over the button and pausing momentarily causes a palette to appear, listing the various controls that you can add to a Windows form. Create a form that resembles the one shown in Figure 4-25 by selecting Button and TextBox controls from the palette and positioning them on the form. Then use the Properties window to apply the following properties to the TextBox:

Property

Value

TextAlign

Right

TabStop

False

Text

“0.00”

ReadOnly

True

BackColor

Window

Cursor

Default

Name

“Display”

Font

10-point Microsoft Sans Serif

Next use the Properties window to assign the following values to the buttons’ Text and Name properties:

Text

Name

Text

Name

“Enter”

“EnterButton”

“1”

“OneButton”

“Fix”

“FixButton”

“2”

“TwoButton”

“Clear”

“ClearButton”

“3”

“ThreeButton”

“Del”

“DeleteButton”

“4”

“FourButton”

“.”

“DecimalButton”

“5”

“FiveButton”

“-“

“SubtractButton”

“6”

“SixButton”

“+”

“AddButton”

“7”

“SevenButton”

“x”

“MultiplyButton”

“8”

“EightButton”

“”

“DivideButton”

“9”

“NineButton”

“0”

“ZeroButton”

Change the font size on the plus, minus, multiply, and divide buttons to 12 points, and then finish up by setting each control’s TabStop property to false. Setting TabStop to false in all the controls (TextBox included) prevents the Tab key from moving the input focus around the form. Sometimes it makes sense to support tabbing between controls. But in step 7, you’ll endow NetCalc with a separate keyboard interface that’s vastly superior to one that merely passes around the input focus.

You just finished designing NetCalc’s user interface. Now it’s time to add the logic that makes NetCalc behave like a calculator.

Figure 4-25
The NetCalc form in Visual Studio .NET’s forms designer.
Step 3: Add Fields

Add the following private fields to the Form1 class. Form1 represents the form you designed in step 2. It was created automatically when the project was created, and it derives from System.Windows.Forms.Form:

Type

Name

Initial Value

Stack

RegStack

new Stack ()

string

FormatString

“f2”

bool

FixPending

False

bool

DecimalInString

False

bool

EntryInProgress

False

const int

MaxChars

21

You can add fields to Form1 by hand, or you can let Visual Studio .NET add them for you. Simply click the Class View tab that appears (by default) near the right edge of the Visual Studio .NET window to display a list of the classes in your project. Then right-click Form1 and select the Add/Add Field command from the ensuing context menu. When the Add Field wizard appears, fill it in with information about the field you want to add. Here’s what the statements that declare and initialize the fields should look like when you’ve finished:

private?Stack?RegStack?=?new?Stack?();
private?string?FormatString?= "f2";
private?bool?FixPending?=?false;
private?bool?DecimalInString?=?false;
private?bool?EntryInProgress?=?false;
private?const?int?MaxChars?=?21;

If you use the Add Field wizard to create these statements, you’ll have to edit them by hand to add the member initializers—for example, "= false". The Add Field wizard won’t add member initializers to fields that aren’t const.

Incidentally, RegStack is an instance of System.Collections.Stack. It represents the calculator’s internal register stack. We’ll use its Push and Pop methods to move values on and off the stack, just like a real RPN calculator. You don’t have to add a

using?System.Collections;

statement to Form1.cs because Visual Studio .NET added it for you.

Step 4: Modify the Form’s Class Constructor

Open Form1.cs and scroll down until you find Form1’s class constructor. Inside that constructor is the following comment:

//
//?TODO:?Add?any?constructor?code?after?InitializeComponent?call
//

Add the following statements after the comment:

RegStack.Push?(0.0);
DisplayXRegister?();

The Push statement initializes the calculator’s internal stack by pushing a 0 onto it. The second statement initializes the calculator’s display by copying the value in the X register (the uppermost item on the stack) to the TextBox control.

Step 5: Add Helper Methods

Add the following helper methods to the Form1 class:

Method Name

Return Type

Parameter List

ProcessDigit

void

int Value

Reset

void

None

ConditionalResetDisplay

void

None

InitializeXRegisterFromDisplay

void

None

DisplayXRegister

void

None

ReportError

void

string Message

You can add these methods by hand (in Form1.cs), or you can add them by right-clicking Form1 in the Class View window and selecting the Add/Add Method command. Make all of the methods private. Fill in the method bodies with the code shown for the finished methods in Figure 4-26. If you use the Add Method command to add these methods, Visual Studio .NET adds empty method bodies for you. It’s still up to you to enter code between the curly braces.

Step 6: Add Click Handlers

Go back to the forms designer and, one by one, double-click (with the left mouse button) the form’s 19 push buttons. Each double-click adds a Click event handler to Form1 and wires the handler to a button. The handlers are named OneButton_Click, TwoButton_Click, and so on. Fill in the empty method bodies with the code in Figure 4-26.

Step 7: Add Keyboard Handlers

NetCalc is now a functional application, but it lacks a keyboard interface. A usable calculator applet must support keystroke entry. To that end, go back to the forms designer and change the form’s KeyPreview property from false to true. Turning KeyPreview on enables the form to see keystrokes before its controls do, even if one of its controls has the input focus.

Next override the following methods in Form1 to trap keyboard events:

Method Name

Return Type

Parameter List

OnKeyPress

void

KeyPressEventArgs e

OnKeyDown

void

KeyEventArgs e

As usual, you can add these methods by hand, or you can add them with the Add Method command. Mark all of these methods protected. If you use Add Method, be sure to check the Override box to include the override keyword in the method declaration. Finish up by implementing these methods as you did the ones shown in Figure 4-26.

Step 8: Override ProcessDialogKey

If you were to build and run NetCalc right now, you’d find that the keyboard interface works only if you use the keyboard exclusively. For example, if you click the 2 button with the mouse and then press Enter on the keyboard, another 2 appears in the calculator window. Why? Because the click sets the input focus to the 2 button, and when a button has the input focus, the system interprets the Enter key to mean that the button should be clicked.

This problem is solved by overriding an obscure method that Form1 inherits from Form. The method is named ProcessDialogKey. It’s called by the framework when certain keys (such as Enter) are pressed to give the form a chance to process the keystroke. Your job is to override the method like this:

protected?override?bool?ProcessDialogKey(Keys?keyData)
{
????return?keyData?==?Keys.Enter??
????????false?:?base.ProcessDialogKey?(keyData);
}

This implementation of ProcessDialogKey performs default processing on keys other than Enter by calling the base class’s implementation of ProcessDialogKey. When the Enter key is pressed, however, ProcessDialogKey refrains from calling the base class to prevent the system from grabbing the keystroke. The Enter key becomes just another key on the keyboard, and pressing it activates your OnKeyDown handler even if a control currently has the input focus.

Step 9: Build and Run the Application

Build the application by selecting the Build command from Visual Studio .NET’s Build menu. Run it by selecting the Start Without Debugging command from the Debug menu (or invoking its keyboard equivalent, Ctrl+F5). Verify that the code is working properly by adding, subtracting, multiplying, and dividing a few numbers. Also click the Fix button followed by the 4 button to change the calculator’s display precision from two places to four. If four numbers appear to the right of the decimal point, you’re set.

The NetCalc Source Code

The finished version of Form1.cs is shown in Figure 4-26. The lines that I typed in are shown in boldface type; all others were generated by Visual Studio .NET. I won’t take the time to analyze each and every line, but I will point out a few highlights:

Visual Studio .NET is a big help in building form-based applications such as NetCalc because it reduces the tedium of sizing and positioning controls and assigning values to control properties. Less tedium means shorter development cycles and faster times to market. That’s a winning proposition no matter how you look at it.

Form1.cs
using?System;
using?System.Drawing;
using?System.Collections;
using?System.ComponentModel;
using?System.Windows.Forms;
using?System.Data;

namespace?NetCalc
{
????///?<summary>
????///?Summary?description?for?Form1.
????///?</summary>
????public?class?Form1?:?System.Windows.Forms.Form
????{
????????private?System.Windows.Forms.Button?FixButton;
????????private?System.Windows.Forms.Button?EnterButton;
????????private?System.Windows.Forms.TextBox?Display;
????????private?System.Windows.Forms.Button?ClearButton;
????????private?System.Windows.Forms.Button?SubtractButton;
????????private?System.Windows.Forms.Button?SevenButton;
????????private?System.Windows.Forms.Button?EightButton;
????????private?System.Windows.Forms.Button?NineButton;
????????private?System.Windows.Forms.Button?FiveButton;
????????private?System.Windows.Forms.Button?FourButton;
????????private?System.Windows.Forms.Button?AddButton;
????????private?System.Windows.Forms.Button?SixButton;
????????private?System.Windows.Forms.Button?ThreeButton;
????????private?System.Windows.Forms.Button?MultiplyButton;
????????private?System.Windows.Forms.Button?OneButton;
????????private?System.Windows.Forms.Button?TwoButton;
????????private?System.Windows.Forms.Button?ZeroButton;
????????private?System.Windows.Forms.Button?DivideButton;
????????private?System.Windows.Forms.Button?DeleteButton;
????????private?System.Windows.Forms.Button?DecimalButton;
????????///?<summary>
????????///?Required?designer?variable.
????????///?</summary>
????????private?System.ComponentModel.Container?components?=?null;

????????public?Form1()
????????{
????????????//
????????????//?Required?for?Windows?Form?Designer?support
????????????//
????????????InitializeComponent();

????????????//
????????????//?TODO:?Add?any?constructor?code?after?InitializeComponent?call
????????????//
????????????RegStack.Push?(0.0);
????????????DisplayXRegister?();
????????}

????????///?<summary>
????????///?Clean?up?any?resources?being?used.
????????///?</summary>
????????protected?override?void?Dispose(?bool?disposing?)
????????{
????????????if(?disposing?)
????????????{
????????????????if?(components?!=?null)?
????????????????{
????????????????????components.Dispose();
????????????????}
????????????}
????????????base.Dispose(?disposing?);
????????}

????????#region?Windows?Form?Designer?generated?code
????????///?<summary>
????????///?Required?method?for?Designer?support?-?do?not?modify
????????///?the?contents?of?this?method?with?the?code?editor.
????????///?</summary>
????????private?void?InitializeComponent()
????????{
????????????this.FixButton?=?new?System.Windows.Forms.Button();
????????????this.EnterButton?=?new?System.Windows.Forms.Button();
????????????this.Display?=?new?System.Windows.Forms.TextBox();
????????????this.ClearButton?=?new?System.Windows.Forms.Button();
????????????this.SubtractButton?=?new?System.Windows.Forms.Button();
????????????this.SevenButton?=?new?System.Windows.Forms.Button();
????????????this.EightButton?=?new?System.Windows.Forms.Button();
????????????this.NineButton?=?new?System.Windows.Forms.Button();
????????????this.FiveButton?=?new?System.Windows.Forms.Button();
????????????this.FourButton?=?new?System.Windows.Forms.Button();
????????????this.AddButton?=?new?System.Windows.Forms.Button();
????????????this.SixButton?=?new?System.Windows.Forms.Button();
????????????this.ThreeButton?=?new?System.Windows.Forms.Button();
????????????this.MultiplyButton?=?new?System.Windows.Forms.Button();
????????????this.OneButton?=?new?System.Windows.Forms.Button();
????????????this.TwoButton?=?new?System.Windows.Forms.Button();
????????????this.ZeroButton?=?new?System.Windows.Forms.Button();
????????????this.DivideButton?=?new?System.Windows.Forms.Button();
????????????this.DeleteButton?=?new?System.Windows.Forms.Button();
????????????this.DecimalButton?=?new?System.Windows.Forms.Button();
????????????this.SuspendLayout();
????????????//?
????????????//?FixButton
????????????//?
????????????this.FixButton.Location?=?new?System.Drawing.Point(112,?57);
????????????this.FixButton.Name?= "FixButton";
????????????this.FixButton.Size?=?new?System.Drawing.Size(40,?32);
????????????this.FixButton.TabIndex?=?14;
????????????this.FixButton.TabStop?=?false;
????????????this.FixButton.Text?= "Fix";
????????????this.FixButton.Click?+=
????????????????new?System.EventHandler(this.FixButton_Click);
????????????//?
????????????//?EnterButton
????????????//?
????????????this.EnterButton.Location?=?new?System.Drawing.Point(16,?57);
????????????this.EnterButton.Name?= "EnterButton";
????????????this.EnterButton.Size?=?new?System.Drawing.Size(88,?32);
????????????this.EnterButton.TabIndex?=?15;
????????????this.EnterButton.TabStop?=?false;
????????????this.EnterButton.Text?= "Enter";
????????????this.EnterButton.Click?+=
????????????????new?System.EventHandler(this.EnterButton_Click);
????????????//?
????????????//?Display
????????????//?
????????????this.Display.BackColor?=?System.Drawing.SystemColors.Window;
????????????this.Display.Cursor?=?System.Windows.Forms.Cursors.Default;
????????????this.Display.Font?=
????????????????new?System.Drawing.Font("Microsoft?Sans?Serif",?9.75F,
????????????????System.Drawing.FontStyle.Regular,
????????????????System.Drawing.GraphicsUnit.Point,?((System.Byte)(0)));
????????????this.Display.Location?=?new?System.Drawing.Point(16,?17);
????????????this.Display.Name?= "Display";
????????????this.Display.ReadOnly?=?true;
????????????this.Display.Size?=?new?System.Drawing.Size(184,?22);
????????????this.Display.TabIndex?=?13;
????????????this.Display.TabStop?=?false;
????????????this.Display.Text?= "0.00";
????????????this.Display.TextAlign?=
????????????????System.Windows.Forms.HorizontalAlignment.Right;
????????????//?
????????????//?ClearButton
????????????//?
????????????this.ClearButton.Location?=?new?System.Drawing.Point(160,?57);
????????????this.ClearButton.Name?= "ClearButton";
????????????this.ClearButton.Size?=?new?System.Drawing.Size(40,?32);
????????????this.ClearButton.TabIndex?=?11;
????????????this.ClearButton.TabStop?=?false;
????????????this.ClearButton.Text?= "Clear";
????????????this.ClearButton.Click?+=
????????????????new?System.EventHandler(this.ClearButton_Click);
????????????//?
????????????//?SubtractButton
????????????//?
????????????this.SubtractButton.Font?=
????????????????new?System.Drawing.Font("Microsoft?Sans?Serif",?12F,
????????????????System.Drawing.FontStyle.Regular,
????????????????System.Drawing.GraphicsUnit.Point,?((System.Byte)(0)));
????????????this.SubtractButton.Location?=?new?System.Drawing.Point(16,?97);
????????????this.SubtractButton.Name?= "SubtractButton";
????????????this.SubtractButton.Size?=?new?System.Drawing.Size(40,?32);
????????????this.SubtractButton.TabIndex?=?12;
????????????this.SubtractButton.TabStop?=?false;
????????????this.SubtractButton.Text?= "-";
????????????this.SubtractButton.Click?+=
????????????????new?System.EventHandler(this.SubtractButton_Click);
????????????//?
????????????//?SevenButton
????????????//?
????????????this.SevenButton.Location?=?new?System.Drawing.Point(64,?97);
????????????this.SevenButton.Name?= "SevenButton";
????????????this.SevenButton.Size?=?new?System.Drawing.Size(40,?32);
????????????this.SevenButton.TabIndex?=?19;
????????????this.SevenButton.TabStop?=?false;
????????????this.SevenButton.Text?= "7";
????????????this.SevenButton.Click?+=
????????????????new?System.EventHandler(this.SevenButton_Click);
????????????//?
????????????//?EightButton
????????????//?
????????????this.EightButton.Location?=?new?System.Drawing.Point(112,?97);
????????????this.EightButton.Name?= "EightButton";
????????????this.EightButton.Size?=?new?System.Drawing.Size(40,?32);
????????????this.EightButton.TabIndex?=?20;
????????????this.EightButton.TabStop?=?false;
????????????this.EightButton.Text?= "8";
????????????this.EightButton.Click?+=
????????????????new?System.EventHandler(this.EightButton_Click);
????????????//?
????????????//?NineButton
????????????//?
????????????this.NineButton.Location?=?new?System.Drawing.Point(160,?97);
????????????this.NineButton.Name?= "NineButton";
????????????this.NineButton.Size?=?new?System.Drawing.Size(40,?32);
????????????this.NineButton.TabIndex?=?18;
????????????this.NineButton.TabStop?=?false;
????????????this.NineButton.Text?= "9";
????????????this.NineButton.Click?+=
????????????????new?System.EventHandler(this.NineButton_Click);
????????????//?
????????????//?FiveButton
????????????//?
????????????this.FiveButton.Location?=?new?System.Drawing.Point(112,?137);
????????????this.FiveButton.Name?= "FiveButton";
????????????this.FiveButton.Size?=?new?System.Drawing.Size(40,?32);
????????????this.FiveButton.TabIndex?=?16;
????????????this.FiveButton.TabStop?=?false;
????????????this.FiveButton.Text?= "5";
????????????this.FiveButton.Click?+=
????????????????new?System.EventHandler(this.FiveButton_Click);
????????????//?
????????????//?FourButton
????????????//?
????????????this.FourButton.Location?=?new?System.Drawing.Point(64,?137);
????????????this.FourButton.Name?= "FourButton";
????????????this.FourButton.Size?=?new?System.Drawing.Size(40,?32);
????????????this.FourButton.TabIndex?=?17;
????????????this.FourButton.TabStop?=?false;
????????????this.FourButton.Text?= "4";
????????????this.FourButton.Click?+=
????????????????new?System.EventHandler(this.FourButton_Click);
????????????//?
????????????//?AddButton
????????????//?
????????????this.AddButton.Font?=
????????????????new?System.Drawing.Font("Microsoft?Sans?Serif",?12F,
????????????????System.Drawing.FontStyle.Regular,
????????????????System.Drawing.GraphicsUnit.Point,?((System.Byte)(0)));
????????????this.AddButton.Location?=?new?System.Drawing.Point(16,?137);
????????????this.AddButton.Name?= "AddButton";
????????????this.AddButton.Size?=?new?System.Drawing.Size(40,?32);
????????????this.AddButton.TabIndex?=?4;
????????????this.AddButton.TabStop?=?false;
????????????this.AddButton.Text?= "+";
????????????this.AddButton.Click?+=
????????????????new?System.EventHandler(this.AddButton_Click);
????????????//?
????????????//?SixButton
????????????//?
????????????this.SixButton.Location?=?new?System.Drawing.Point(160,?137);
????????????this.SixButton.Name?= "SixButton";
????????????this.SixButton.Size?=?new?System.Drawing.Size(40,?32);
????????????this.SixButton.TabIndex?=?5;
????????????this.SixButton.TabStop?=?false;
????????????this.SixButton.Text?= "6";
????????????this.SixButton.Click?+=
????????????????new?System.EventHandler(this.SixButton_Click);
????????????//?
????????????//?ThreeButton
????????????//?
????????????this.ThreeButton.Location?=?new?System.Drawing.Point(160,?177);
????????????this.ThreeButton.Name?= "ThreeButton";
????????????this.ThreeButton.Size?=?new?System.Drawing.Size(40,?32);
????????????this.ThreeButton.TabIndex?=?3;
????????????this.ThreeButton.TabStop?=?false;
????????????this.ThreeButton.Text?= "3";
????????????this.ThreeButton.Click?+=
????????????????new?System.EventHandler(this.ThreeButton_Click);
????????????//?
????????????//?MultiplyButton
????????????//?
????????????this.MultiplyButton.Font?=
????????????????new?System.Drawing.Font("Microsoft?Sans?Serif",?12F,
????????????????System.Drawing.FontStyle.Regular,
????????????????System.Drawing.GraphicsUnit.Point,?((System.Byte)(0)));
????????????this.MultiplyButton.Location?=?new?System.Drawing.Point(16,?177);
????????????this.MultiplyButton.Name?= "MultiplyButton";
????????????this.MultiplyButton.Size?=?new?System.Drawing.Size(40,?32);
????????????this.MultiplyButton.TabIndex?=?1;
????????????this.MultiplyButton.TabStop?=?false;
????????????this.MultiplyButton.Text?= "x";
????????????this.MultiplyButton.Click?+=
????????????????new?System.EventHandler(this.MultiplyButton_Click);
????????????//?
????????????//?OneButton
????????????//?
????????????this.OneButton.Location?=?new?System.Drawing.Point(64,?177);
????????????this.OneButton.Name?= "OneButton";
????????????this.OneButton.Size?=?new?System.Drawing.Size(40,?32);
????????????this.OneButton.TabIndex?=?2;
????????????this.OneButton.TabStop?=?false;
????????????this.OneButton.Text?= "1";
????????????this.OneButton.Click?+=
????????????????new?System.EventHandler(this.OneButton_Click);
????????????//?
????????????//?TwoButton
????????????//?
????????????this.TwoButton.Location?=?new?System.Drawing.Point(112,?177);
????????????this.TwoButton.Name?= "TwoButton";
????????????this.TwoButton.Size?=?new?System.Drawing.Size(40,?32);
????????????this.TwoButton.TabIndex?=?9;
????????????this.TwoButton.TabStop?=?false;
????????????this.TwoButton.Text?= "2";
????????????this.TwoButton.Click?+=
????????????????new?System.EventHandler(this.TwoButton_Click);
????????????//?
????????????//?ZeroButton
????????????//?
????????????this.ZeroButton.Location?=?new?System.Drawing.Point(64,?217);
????????????this.ZeroButton.Name?= "ZeroButton";
????????????this.ZeroButton.Size?=?new?System.Drawing.Size(40,?32);
????????????this.ZeroButton.TabIndex?=?10;
????????????this.ZeroButton.TabStop?=?false;
????????????this.ZeroButton.Text?= "0";
????????????this.ZeroButton.Click?+=
????????????????new?System.EventHandler(this.ZeroButton_Click);
????????????//?
????????????//?DivideButton
????????????//?
????????????this.DivideButton.Font?=
????????????????new?System.Drawing.Font("Microsoft?Sans?Serif",?12F,
????????????????System.Drawing.FontStyle.Regular,
????????????????System.Drawing.GraphicsUnit.Point,?((System.Byte)(0)));
????????????this.DivideButton.Location?=?new?System.Drawing.Point(16,?217);
????????????this.DivideButton.Name?= "DivideButton";
????????????this.DivideButton.Size?=?new?System.Drawing.Size(40,?32);
????????????this.DivideButton.TabIndex?=?8;
????????????this.DivideButton.TabStop?=?false;
????????????this.DivideButton.Text?= "";
????????????this.DivideButton.Click?+=
????????????????new?System.EventHandler(this.DivideButton_Click);
????????????//?
????????????//?DeleteButton
????????????//?
????????????this.DeleteButton.Location?=?new?System.Drawing.Point(160,?217);
????????????this.DeleteButton.Name?= "DeleteButton";
????????????this.DeleteButton.Size?=?new?System.Drawing.Size(40,?32);
????????????this.DeleteButton.TabIndex?=?6;
????????????this.DeleteButton.TabStop?=?false;
????????????this.DeleteButton.Text?= "Del";
????????????this.DeleteButton.Click?+=
????????????????new?System.EventHandler(this.DeleteButton_Click);
????????????//?
????????????//?DecimalButton
????????????//?
????????????this.DecimalButton.Location?=?new?System.Drawing.Point(112,?217);
????????????this.DecimalButton.Name?= "DecimalButton";
????????????this.DecimalButton.Size?=?new?System.Drawing.Size(40,?32);
????????????this.DecimalButton.TabIndex?=?7;
????????????this.DecimalButton.TabStop?=?false;
????????????this.DecimalButton.Text?= ".";
????????????this.DecimalButton.Click?+=
????????????????new?System.EventHandler(this.DecimalButton_Click);
????????????//?
????????????//?Form1
????????????//?
????????????this.AutoScaleBaseSize?=?new?System.Drawing.Size(5,?13);
????????????this.ClientSize?=?new?System.Drawing.Size(218,?266);
????????????this.Controls.AddRange(new?System.Windows.Forms.Control[]?{
????????????????this.FixButton,
????????????????this.EnterButton,
????????????????this.Display,
????????????????this.ClearButton,
????????????????this.SubtractButton,
????????????????this.SevenButton,
????????????????this.EightButton,
????????????????this.NineButton,
????????????????this.FiveButton,
????????????????this.FourButton,
????????????????this.AddButton,
????????????????this.SixButton,
????????????????this.ThreeButton,
????????????????this.MultiplyButton,
????????????????this.OneButton,
????????????????this.TwoButton,
????????????????this.ZeroButton,
????????????????this.DivideButton,
????????????????this.DeleteButton,
????????????????this.DecimalButton});
????????????this.FormBorderStyle?=
????????????????System.Windows.Forms.FormBorderStyle.FixedDialog;
????????????this.KeyPreview?=?true;
????????????this.MaximizeBox?=?false;
????????????this.Name?= "Form1";
????????????this.Text?= "NetCalc";
????????????this.ResumeLayout(false);
????????}
????????#endregion

????????///?<summary>
????????///?The?main?entry?point?for?the?application.
????????///?</summary>
?????????[STAThread]
????????static?void?Main()?
????????{
????????????Application.Run(new?Form1());
????????}

????????private?Stack?RegStack?=?new?Stack?();
????????private?string?FormatString?= "f2";
????????private?bool?FixPending?=?false;
????????private?bool?DecimalInString?=?false;
????????private?bool?EntryInProgress?=?false;
????????private?const?int?MaxChars?=?21;

????????//
????????//?Process?a?press?of?one?of?the?numeric?buttons.?If?Fix?was
????????//?the?last?button?pressed,?change?the?calculator's?output
????????//?precision?by?modifying?FormatString.?Otherwise,?reset?the
????????//?display?if?necessary?and?append?the?number?to?any?numbers
????????//?previously?entered.
????????//
????????private?void?ProcessDigit(int?Value)
????????{
????????????if?(FixPending)?{
????????????????FormatString?= "f" +?Value.ToString?();
????????????????if?(EntryInProgress)
????????????????????InitializeXRegisterFromDisplay?();
????????????????DisplayXRegister?();
????????????????FixPending?=?false;
????????????}
????????????else?{
????????????????ConditionalResetDisplay?();
????????????????if?(Display.Text.Length?<?MaxChars)
????????????????????Display.Text?+=?Value.ToString?();
????????????}
????????}

????????//
????????//?Reset?the?calculator's?internal?flags.
????????//
????????private?void?Reset()
????????{
????????????DecimalInString?=?false;
????????????FixPending?=?false;
????????????EntryInProgress?=?false;
????????}

????????//
????????//?Blank?out?the?value?displayed?in?the?calculator?window
????????//?if?an?entry?isn't?already?in?progress.
????????//
????????private?void?ConditionalResetDisplay()
????????{
????????????if?(!EntryInProgress)?{
????????????????EntryInProgress?=?true;
????????????????Display.Text?= "";
????????????}
????????}

????????//
????????//?Convert?the?text?in?the?calculator?display?to?a?numeric
????????//?value?and?push?it?onto?the?stack.
????????//
????????private?void?InitializeXRegisterFromDisplay()
????????{
????????????double?x?=?(Display.Text.Length?==?0?││?Display.Text?== ".")??
????????????????0.0?:?Convert.ToDouble?(Display.Text);
????????????RegStack.Push?(x);
????????}

????????//
????????//?Show?the?value?at?the?top?of?the?stack?in?the?calculator
????????//?window.?Check?for?overflow?and?underflow?and?display?an
????????//?error?message?if?either?has?occurred.
????????//
????????private?void?DisplayXRegister()
????????{
????????????double?x?=?(double)?RegStack.Peek?();
????????????if?(x?>?Double.MaxValue?││?x?<?Double.MinValue)
????????????????ReportError?("Overflow");
????????????else?{
????????????????string?display?=?x.ToString?(FormatString);
????????????????if?(display.Length?>?MaxChars?││
????????????????????(Math.Abs?(x)?>?0.0?&&?Math.Abs?(x)?<?0.0000000001))
????????????????????display?=?x.ToString?("e");
????????????????Display.Text?=?display;
????????????}
????????}

????????//
????????//?Report?an?error?to?the?user?by?displaying?an?error
????????//?message?in?the?calculator?window.?Also?reset?the
????????//?calculator's?internal?state?so?the?next?button?press
????????//?will?start?things?over?again.
????????//
????????private?void?ReportError(string?Message)
????????{
????????????Display.Text?=?Message;
????????????RegStack.Clear?();
????????????RegStack.Push?(0.0);
????????????Reset?();
????????}

????????//
????????//?Handlers?for?the?calculator's?numeric?buttons?(0-9).
????????//
????????private?void?ZeroButton_Click(object?sender,?System.EventArgs?e)
????????{
????????????ProcessDigit?(0);
????????}

????????private?void?OneButton_Click(object?sender,?System.EventArgs?e)
????????{
????????????ProcessDigit?(1);
????????}

????????private?void?TwoButton_Click(object?sender,?System.EventArgs?e)
????????{
????????????ProcessDigit?(2);
????????}

????????private?void?ThreeButton_Click(object?sender,?System.EventArgs?e)
????????{
????????????ProcessDigit?(3);
????????}

????????private?void?FourButton_Click(object?sender,?System.EventArgs?e)
????????{
????????????ProcessDigit?(4);
????????}

????????private?void?FiveButton_Click(object?sender,?System.EventArgs?e)
????????{
????????????ProcessDigit?(5);
????????}

????????private?void?SixButton_Click(object?sender,?System.EventArgs?e)
????????{
????????????ProcessDigit?(6);
????????}

????????private?void?SevenButton_Click(object?sender,?System.EventArgs?e)
????????{
????????????ProcessDigit?(7);
????????}

????????private?void?EightButton_Click(object?sender,?System.EventArgs?e)
????????{
????????????ProcessDigit?(8);
????????}

????????private?void?NineButton_Click(object?sender,?System.EventArgs?e)
????????{
????????????ProcessDigit?(9);
????????}

????????//
????????//?Handlers?for?the?Add,?Subtract,?Multiply,?and
????????//?Divide?buttons.
????????//
????????//?General?strategy?employed?by?all?four?handlers:
????????//?1)?Push?the?value?in?the?calculator?display?onto?the
????????//????stack?if?it?hasn't?been?pushed?already.
????????//?2)?Pop?two?values?from?the?stack?to?use?as?operands.
????????//?3)?Compute?the?sum,?difference,?product,?or?quotient.
????????//?4)?Push?the?result?onto?the?stack.
????????//?5)?Display?the?result.
????????//
????????private?void?SubtractButton_Click(object?sender,?System.EventArgs?e)
????????{
????????????if?(EntryInProgress)
????????????????InitializeXRegisterFromDisplay?();

????????????if?(RegStack.Count?>=?2)?{
????????????????double?op1?=?(double)?RegStack.Pop?();
????????????????double?op2?=?(double)?RegStack.Pop?();
????????????????RegStack.Push?(op2?-?op1);
????????????????DisplayXRegister?();
????????????????Reset?();
????????????}
????????}

????????private?void?AddButton_Click(object?sender,?System.EventArgs?e)
????????{
????????????if?(EntryInProgress)
????????????????InitializeXRegisterFromDisplay?();

????????????if?(RegStack.Count?>=?2)?{
????????????????double?op1?=?(double)?RegStack.Pop?();
????????????????double?op2?=?(double)?RegStack.Pop?();
????????????????RegStack.Push?(op2?+?op1);
????????????????DisplayXRegister?();
????????????????Reset?();
????????????}
????????}

????????private?void?MultiplyButton_Click(object?sender,?System.EventArgs?e)
????????{
????????????if?(EntryInProgress)
????????????????InitializeXRegisterFromDisplay?();

????????????if?(RegStack.Count?>=?2)?{
????????????????double?op1?=?(double)?RegStack.Pop?();
????????????????double?op2?=?(double)?RegStack.Pop?();
????????????????RegStack.Push?(op2?*?op1);
????????????????DisplayXRegister?();
????????????????Reset?();
????????????}
????????}

????????private?void?DivideButton_Click(object?sender,?System.EventArgs?e)
????????{
????????????if?(EntryInProgress)
????????????????InitializeXRegisterFromDisplay?();

????????????if?(RegStack.Count?>=?2)?{
????????????????if?((double)?RegStack.Peek?()?==?0.0)
????????????????????ReportError?("Divide?by?zero");
????????????????else?{
????????????????????double?op1?=?(double)?RegStack.Pop?();
????????????????????double?op2?=?(double)?RegStack.Pop?();
????????????????????RegStack.Push?(op2?/?op1);
????????????????????DisplayXRegister?();
????????????????????Reset?();
????????????????}
????????????}
????????}

????????//
????????//?Handler?for?the?Enter?button.
????????//
????????private?void?EnterButton_Click(object?sender,?System.EventArgs?e)
????????{
????????????InitializeXRegisterFromDisplay?();
????????????DisplayXRegister?();
????????????Reset?();
????????}

????????//
????????//?Handler?for?the?Fix?button.
????????//
????????private?void?FixButton_Click(object?sender,?System.EventArgs?e)
????????{
????????????FixPending?=?!FixPending;
????????}

????????//
????????//?Handler?for?the?Clear?button.
????????//
????????private?void?ClearButton_Click(object?sender,?System.EventArgs?e)
????????{
????????????RegStack.Clear?();
????????????RegStack.Push?(0.0);
????????????DisplayXRegister?();
????????????Reset?();
????????}

????????//
????????//?Handler?for?the?Delete?button.
????????//
????????private?void?DeleteButton_Click(object?sender,?System.EventArgs?e)
????????{
????????????int?len?=?Display.Text.Length;
????????????if?(len?>?0?&&?EntryInProgress)?{
????????????????if?(Display.Text[len?-?1]?==?'.')
????????????????????DecimalInString?=?false;
????????????????Display.Text?=?Display.Text.Substring?(0,?len?-?1);
????????????}
????????}

????????//
????????//?Handler?for?the?'.'?button.
????????//
????????private?void?DecimalButton_Click(object?sender,?System.EventArgs?e)
????????{
????????????ConditionalResetDisplay?();
????????????if?(Display.Text.Length?<?MaxChars?&&?!DecimalInString)?{
????????????????Display.Text?+= ".";
????????????????DecimalInString?=?true;
????????????}
????????}

????????//
????????//?Handler?for?KeyPress?events.?Comprises?half?of?NetCalc's
????????//?keyboard?interface.
????????//
????????protected?override?void?OnKeyPress(KeyPressEventArgs?e)
????????{
????????????switch?(e.KeyChar)?{

????????????case?'0':
????????????????ZeroButton_Click?(ZeroButton,?new?EventArgs?());
????????????????break;

????????????case?'1':
????????????????OneButton_Click?(OneButton,?new?EventArgs?());
????????????????break;

????????????case?'2':
????????????????TwoButton_Click?(TwoButton,?new?EventArgs?());
????????????????break;

????????????case?'3':
????????????????ThreeButton_Click?(ThreeButton,?new?EventArgs?());
????????????????break;

????????????case?'4':
????????????????FourButton_Click?(FourButton,?new?EventArgs?());
????????????????break;

????????????case?'5':
????????????????FiveButton_Click?(FiveButton,?new?EventArgs?());
????????????????break;

????????????case?'6':
????????????????SixButton_Click?(SixButton,?new?EventArgs?());
????????????????break;

????????????case?'7':
????????????????SevenButton_Click?(SevenButton,?new?EventArgs?());
????????????????break;

????????????case?'8':
????????????????EightButton_Click?(EightButton,?new?EventArgs?());
????????????????break;

????????????case?'9':
????????????????NineButton_Click?(NineButton,?new?EventArgs?());
????????????????break;

????????????case?'.':
????????????????DecimalButton_Click?(DecimalButton,?new?EventArgs?());
????????????????break;

????????????case?'-':
????????????????SubtractButton_Click?(SubtractButton,?new?EventArgs?());
????????????????break;

????????????case?'+':
????????????????AddButton_Click?(AddButton,?new?EventArgs?());
????????????????break;

????????????case?'*':
????????????????MultiplyButton_Click?(MultiplyButton,?new?EventArgs?());
????????????????break;

????????????case?'/':
????????????????DivideButton_Click?(DivideButton,?new?EventArgs?());
????????????????break;
????????????}
????????}

????????//
????????//?Handler?for?KeyDown?events.?The?other?half?of?NetCalc's
????????//?keyboard?interface.
????????//
????????protected?override?void?OnKeyDown(KeyEventArgs?e)
????????{
????????????switch?(e.KeyCode)?{

????????????case?Keys.C:
????????????????ClearButton_Click?(ClearButton,?new?EventArgs?());
????????????????break;
				
????????????case?Keys.F:
????????????????FixButton_Click?(FixButton,?new?EventArgs?());
????????????????break;
				
????????????case?Keys.Enter:
????????????????EnterButton_Click?(EnterButton,?new?EventArgs?());
????????????????break;
				
????????????case?Keys.Delete:
????????????????DeleteButton_Click?(DeleteButton,?new?EventArgs?());
????????????????break;						
????????????}
????????}

????????//
????????//?The?following?override?prevents?the?form?from "stealing"
????????//?the?Enter?key?and?using?it?to?simulate?button?clicks.
????????//
????????protected?override?bool?ProcessDialogKey(Keys?keyData)
????????{
????????????return?keyData?==?Keys.Enter??
????????????????false?:?base.ProcessDialogKey?(keyData);
????????}
????}
}
Figure 4-26
The NetCalc source code.