The previous chapters have used console applications to demonstrate C# and the Common Language Runtime. Although console applications can be implemented simply, it is time to turn your attention to the reason you’re learning the C# language in the first place: building Windows and web applications.
In the early days of Windows computing, an application ran on a desktop, in splendid isolation. Over time, developers found it beneficial to spread their applications across a network, with the user interface on one computer and a database on another. This division of responsibilities or partitioning of an application came to be called two-tier or client-server application development. Later three-tier or n-tier approaches emerged as developers began to use web servers to host business objects that could handle the database access on behalf of clients.
When the Web first came along, there was a clear distinction between Windows applications and web applications. Windows applications ran on the desktop or a local-area network (LAN), and web applications ran on a distant server and were accessed by a browser. This distinction is now being blurred as Windows applications reach out to the Web for services. Many new applications consist of logic running on a client, a database server, and remote third-party computers located on the Web. Traditional desktop applications such as Excel or Outlook are now able to integrate data retrieved through web connections seamlessly, and web applications can distribute some of their processing to client-side components.
The primary remaining distinction between a Windows application and a web application might be this: who owns the user interface? Will your application use a browser to display its user interface, or will the UI be built into the executable running on the desktop?
There are enormous advantages to web applications, starting with the obvious: they can be accessed from any browser that can connect to the server. In addition, updates can be made at the server, without the need to distribute new dynamic link libraries (DLLs) to your customers.
On the other hand, if your application derives no benefit from being on the Web, you might find that you can achieve greater control over the look and feel of your application, or you can achieve better performance, by building a desktop application.
.NET offers closely related, but distinguishable, suites of tools for building Windows or web applications. Both are based on forms, with the premise that many applications have user interfaces centered on interacting with the user through forms and controls, such as buttons, list boxes, text, and so forth.
The tools for creating web applications are called Web-Forms and are considered in Chapter 15. The tools for creating Windows applications are called Windows Forms and are the subject of this chapter.
It is my prediction that the distinction between Web-Forms and Windows Forms is temporary. There is such obvious similarity between these two approaches that I’d be very surprised if the next version of .NET didn’t merge these two tools into one unified development environment.
In the following pages, you will learn how to create a simple Windows Form using either a text editor such as Notepad or the Design tool in Visual Studio.NET. Next you will build a more complex Windows application using Visual Studio, the Windows Forms framework, and a number of C# programming techniques you learned in earlier chapters. The chapter concludes with a brief introduction to Documentation Comments, a new XML-facilitated means to document applications, and an introduction to the deployment of .NET applications.
A Windows Form is a tool for building a Windows application. The .NET Framework offers extensive support for Windows application development, the centerpiece of which is the Windows Forms framework. Not surprisingly, Windows Forms use the metaphor of a form. This idea was borrowed from the wildly successful Visual Basic (VB) environment and supports Rapid Application Development (RAD). Arguably, C# is the first development environment to marry the RAD tools of Visual Basic with the object-oriented and high-performance characteristics of a C-family language.
Visual Studio.NET provides a rich set of drag-and-drop tools for working with Windows Forms. It is possible to build a Windows application without using the Visual Studio Integrated Development Environment (IDE), but it is far more painful and takes a lot longer.
However, just to prove the point, you’ll use Notepad to create a simple Windows Form application that displays text in a window and implements a Cancel button. The application display is shown in Figure 13-1.
You start by adding a using
statement for the
Windows Forms namespace:
using System.Windows.Forms;
The key to creating a Windows Form application is to derive your form
from System.Windows.Forms.Form:
public class HandDrawnClass : Form
The Form
object represents any window displayed
in your application. You can use the Form
class to
create standard windows, as well as floating windows, tools, dialog
boxes, and so forth. Microsoft apparently chose to call this a form
rather than a window to emphasize that most windows now have an
interactive component that includes controls for interacting with
users.
All the Windows widgets you’ll need (labels, buttons, list
boxes, etc.) are found within the Windows.Forms
namespace. In the IDE, you’ll be able to drag and drop these
objects onto a designer, but for now you’ll declare them right
in your program code.
To get started, declare the two
widgets you need, a label to hold the
Hello
World
text and a button
to exit the application:
private System.Windows.Forms.Label lblOutput; private System.Windows.Forms.Button btnCancel;
You’re now ready to instantiate these objects, which you do in your Form’s constructor:
this.lblOutput = new System.Windows.Forms.Label( ); this.btnCancel = new System.Windows.Forms.Button( );
Next you can set the Form
’s title text to
Hello World
:
this.Text = "Hello World";
Note that the preceding statements appear in your form’s
constructor, HandDrawnClass
, and so the
this
keyword refers to the form itself.
Set the label’s location, text, and size:
lblOutput.Location = new System.Drawing.Point (16, 24); lblOutput.Text = "Hello World!"; lblOutput.Size = new System.Drawing.Size (216, 24);
The location is expressed as a
System.Drawing.Point
object, whose constructor takes a
horizontal
and vertical
position. The size is set with a Size
object,
whose constructor takes a pair of integers that represent the
width
and height
of the object.
The .NET Framework provides the System.Drawing
object, which encapsulates the Win32 GID+ graphics functions. Much of
the .NET Framework Class Library (
FCL) consists of classes
that encapsulate Win32 methods as objects.
Next, do the same for the
button
object, setting its location, size, and text:
btnCancel.Location = new System.Drawing.Point (150,200); btnCancel.Size = new System.Drawing.Size (112, 32); btnCancel.Text = "&Cancel";
The button also needs an event handler. As described in Chapter 12, events (in this case the cancel button-click
event) are implemented using delegates. The
publishing class
(button
) defines a delegate
(System.EventHandler
) that the subscribing class
(your form) must implement.
The delegated method can have any name but must return
void
and take two parameters: an object
(sender
) and a
SystemEventArgs
object, typically named
e
:
protected void btnCancel_Click ( object sender, System.EventArgs e) { //... }
You register your event handler method in two steps. First you create
a new System.EventHandler
delegate, passing in the
name of your method as a parameter:
new System.EventHandler (this.btnCancel_Click);
You then add that delegate to the button’s click event handler
list with the +=
operator.
The following line combines these steps into one:
one:btnCancel.Click += new System.EventHandler (this.btnCancel_Click);
Now you must set up the form’s dimensions. The form property
AutoScaleBaseSize
sets the base size used at
display time to compute the scaling factor for the form. The
ClientSize
property sets the size of the
form’s client area, which is the size of the form excluding
borders and titlebar (when you use the designer, these values are
provided for you interactively):
this.AutoScaleBaseSize = new System.Drawing.Size (5, 13); this.ClientSize = new System.Drawing.Size (300, 300);
Finally, remember to add the widgets to the form:
this.Controls.Add (this.btnCancel); this.Controls.Add (this.lblOutput);
Having registered the event handler, you must supply the
implementation. For this example, clicking Cancel will exit the
application, using the static method Exit( )
of
the Application
class:
protected void btnCancel_Click ( object sender, System.EventArgs e) { Application.Exit ( ); }
That’s it; you just need an entry point to invoke the constructor on the form:
public static void Main( ) { Application.Run(new HandDrawnClass( )); }
The complete source is shown in Example 13-1. When you run this application, the window is opened and the text is displayed. Pressing Cancel closes the application.
Example 13-1. Creating a hand-drawn Windows Form
using System; using System.Windows.Forms; namespace ProgCSharp { public class HandDrawnClass : Form { // a label to display Hello World private System.Windows.Forms.Label lblOutput; // a cancel button private System.Windows.Forms.Button btnCancel; public HandDrawnClass( ) { // create the objects this.lblOutput = new System.Windows.Forms.Label ( ); this.btnCancel = new System.Windows.Forms.Button ( ); // set the form's title this.Text = "Hello World"; // set up the output label lblOutput.Location = new System.Drawing.Point (16, 24); lblOutput.Text = "Hello World!"; lblOutput.Size = new System.Drawing.Size (216, 24); // set up the cancel button btnCancel.Location = new System.Drawing.Point (150,200); btnCancel.Size = new System.Drawing.Size (112, 32); btnCancel.Text = "&Cancel"; // set up the event handler btnCancel.Click += new System.EventHandler (this.btnCancel_Click); // Add the controls and set the client area this.AutoScaleBaseSize = new System.Drawing.Size (5, 13); this.ClientSize = new System.Drawing.Size (300, 300); this.Controls.Add (this.btnCancel); this.Controls.Add (this.lblOutput); } // handle the cancel event protected void btnCancel_Click ( object sender, System.EventArgs e) { Application.Exit( ); } // Run the app public static void Main( ) { Application.Run(new HandDrawnClass( )); } } }
Although hand coding is always great fun, it is also a lot of work, and the result in the previous example is not as elegant as most programmers would expect. The Visual Studio IDE provides a design tool for Windows Forms that is much easier to use.
To begin work on a new Windows application, first open Visual Studio
and choose New Project. In the New Project window, create
a new C# Windows application and name it
ProgCSharpWindowsForm
, as shown in Figure 13-2.
Visual Studio responds by creating a Windows Form application and, best of all, putting you into a design environment as shown in Figure 13-3.
The Design window displays a blank Windows Form
(Form1
). A Toolbox window is also
available, with a selection of Windows widgets and controls. If the
Toolbox is not displayed, try clicking the word
“Toolbox,” or select View → Toolbox on the Visual
Studio menu. You can also use the keyboard shortcut Ctrl-Alt-X to
display the Toolbox. With the Toolbox displayed, you can drag a label
and a button directly onto the form, as shown in Figure 13-4.
Before proceeding, take a look around. The Toolbox is filled with
controls that you can add to your Windows Form application. In the
upper-right corner you should see the Solution Explorer, a window
which displays all the files in your projects. In the lower-right
corner is the Properties window, which displays all the properties of
the currently selected item. In Figure 13-4, the
label (label1
) is selected, and the Properties
window displays its properties.
You can use the Properties window to set the static properties of the
various controls. For example, to add text to
label1
, you can type the words “Hello
World” into the box to the right of its Text
property. If you want to change the font for the lettering in the
HelloWorld
label, you click the Font property
shown in the lower-right corner of Figure 13-5. (You
can provide text in the same way for your button
(button1
) by selecting it in the Property window
and typing the word “Cancel” into its
Text
property.)
Any one of these steps is much easier than modifying these properties in code (though that is certainly still possible).
Once you have the form laid out the way you want, all that remains is
to create an event handler for the Cancel button. Double-clicking the
Cancel button will create the event handler, register it, and put you
on the code-behind
page (the page that holds the
source code for this form), where you can enter the event handling
logic, as shown in Figure 13-6.
The cursor is already in place; you have only to enter the one line of code:
Application.Exit( );
In the IDE, the cursor flashes, making it very easy to see where the code goes. For most readers, the cursor probably will not flash in this book.
Visual Studio.NET generates all the code necessary to create and initialize the components. The complete source code is shown in Example 13-2, including the one line of code you provided (shown in bold in this example) to handle the Cancel button-click event.
Example 13-2. Source code generated by the IDE
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace ProgCSharpWindowsForm
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Label lblOutput;
private System.Windows.Forms.Button btnCancel;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container
components;
public Form1( )
{
//
// Required for Windows Form Designer support
//
InitializeComponent( );
//
// TODO: Add any constructor code
// after InitializeComponent call
//
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
public override void Dispose( )
{
base.Dispose( );
if(components != null)
components.Dispose( );
}
#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.lblOutput = new System.Windows.Forms.Label( );
this.btnCancel = new System.Windows.Forms.Button( );
this.SuspendLayout( );
//
// lblOutput
//
this.lblOutput.Font = new System.Drawing.Font("Arial", 15.75F,
System.Drawing.FontStyle.Bold,
System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.lblOutput.Location = new System.Drawing.Point(24, 16);
this.lblOutput.Name = "lblOutput";
this.lblOutput.Size = new System.Drawing.Size(136, 48);
this.lblOutput.TabIndex = 0;
this.lblOutput.Text = "Hello World";
//
// btnCancel
//
this.btnCancel.Location = new System.Drawing.Point(192, 208);
this.btnCancel.Name = "btnCancel";
this.btnCancel.TabIndex = 1;
this.btnCancel.Text = "Cancel";
this.btnCancel.Click += new System.EventHandler(
this.btnCancel_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 273);
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.btnCancel, this.lblOutput});
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
private void btnCancel_Click(object sender, System.EventArgs e)
{
Application.Exit( );
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main( )
{
Application.Run(new Form1( ));
}
}
}
There is quite a bit of code in this listing that did not appear in; though most of it is not terribly important. When Visual Studio creates the application, it must add some boilerplate code that is not essential for this simple application.
A careful examination reveals that the essentials are the same, but there are some key differences worth examining. The listing starts with special comment marks:
/// <summary> /// Summary description for Form1. /// </summary>
These marks are used for creating documentation; they are explained in detail later in this chapter.
The form derives from System.Windows.Forms.Form
as
did our earlier example. The widgets are defined as in the previous
example:
public class Form1 : System.Windows.Forms.Form { private System.Windows.Forms.Label lblOutput; private System.Windows.Forms.Button btnCancel;
The designer creates a private container
variable
for its own use:
private System.ComponentModel.Container components;
In this and in every Windows Form application generated by Visual
Studio .NET, the constructor calls a private method,
InitializeComponent( )
, which is used to define and set the
properties of all the controls. The properties are set based on the
values you’ve chosen (or on the default values you’ve
left alone) in the designer. The InitializeComponent( )
method is marked with a comment that you should not
modify the contents of this method; making changes to this method
might confuse the designer.
This program will behave exactly as your earlier hand-crafted application did.
3.144.100.237