Developing a Simple Windows Forms Project

Developing a Simple Windows Forms Project

To create a Windows Forms project, begin by opening the New Project dialog box and selecting Windows Application, as shown in Figure 11-1. Clicking the OK button will cause Microsoft Visual C# .NET to automatically generate a basic Windows Forms project for you, including a simple main form for the top-level window and other associated files.

Figure 11-1.
Creating a Windows Forms project with Visual C# .NET.
Examining Files Created by Visual C# .NET

The project directory contains a number of files that are used to create the compiled assembly for your application. For a basic project such as SimpleForm, the generated files are as follows:

  • App.ico  The default icon for the application

  • AssemblyInfo.cs  A C# source file that contains attribute declarations that target the assembly generated by the project

  • Form1.cs  The primary C# source file for the project

  • Form1.resx  An XML file that stores some resource information associated with Form1.cs

  • SimpleForm.csproj  The primary Visual C# project file

  • SimpleForm.csproj.user  A Visual C# project file that contains user-specific settings

  • SimpleForm.sln  The primary Visual C# solution file

  • SimpleForm.suo  A Visual C# solution file that contains user-specific­ information

Of these files, only the Form1.cs and AssemblyInfo.cs files contain C# source code. As with the console applications discussed in Part I and Part II, the AssemblyInfo.cs file contains only assembly attributes that define the characteristics of the compiled assembly. Most of the C# code for a new project is found in the Form1.cs file. When a source file that implements a form is opened, the form is initially displayed in design mode, as shown in Figure 11-2.

Figure 11-2.
A form in the Visual C# Forms Designer.

To view the C# source code for a form, press F7, or right-click the form and choose View Code from the shortcut menu. Either action will cause the source code to be displayed for editing while Visual C# .NET keeps your form open in design mode on a separate tab. The contents of Form1.cs are shown here, with some comments removed for clarity:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace SimpleForm
{
    public class Form1 : System.Windows.Forms.Form
    {
        private System.ComponentModel.Container components = null;

        public Form1()
        {
            InitializeComponent();
        }

        /// <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.components = new System.ComponentModel.Container();
            this.Size = new System.Drawing.Size(300,300);
            this.Text = "Form1";
        }
        #endregion

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

The preceding source code looks a lot like the source code used in the console applications presented earlier in this book, with a few differences. One of these differences is that the using statements at the top of the file reference a number of namespaces that are commonly used in Windows Forms applications, including the following:

  • System.Collections  As discussed in Chapter 8, the Collections namespace includes classes that provide collection-style containment for other types.

  • System.ComponentModel  Includes classes that implement container and control behavior. A form uses an instance of System.ComponentModel.Container to track the components used by the form.

  • System.Data  Includes classes that are used for Microsoft ADO.NET database access. This namespace isn’t used in a default application, so you can safely remove the using statement for this namespace if you’re not programming with ADO.NET.

  • System.Drawing  Includes classes that provide access to basic GDI+ drawing functions. The use of classes in this namespace and GDI+ are discussed in more detail in Chapter 14.

  • System.Windows.Forms  Includes all of the Windows Forms classes, enabling you to call the types in this namespace by their shorter, friendlier names.

Another difference between a Windows Forms application and a console application is that the Form1 class is derived from the System.Windows.Forms.Form base class. As mentioned, this class serves as a base class for all form windows that you create in a .NET application.

One section of the source file is protected by #region and #endregion preprocessor directives, which define collapsible code regions for the Code Editor. This particular region includes source code that’s used by the Forms Designer to store properties and other configuration information for the form, as well as any child controls owned by the form. When the designer-related code is enclosed in a region, it can be collapsed by default and protected from inadvertent editing. To view this code in the Code Editor, click the small plus sign (+) adjacent to the highlighted region labeled Windows Form Designer generated code.

The Main method in a Windows Forms application includes a call to Application.Run, as shown here:

static void Main() 
{
    Application.Run(new Form1());
}

As you’ll see later in this chapter, in the section “Starting an Application,” the Run method will start the message loop required by all Windows applications and will display the main form for the application. When the application’s main form is closed, the Run method will return.

Finally, because all form classes interact with operating system handles (specifically window handles), every form class implements the Dispose method. If you add resources that require disposal to a form class, you should arrange for their disposal inside the Dispose method.

note

Remember, you can reference managed resources only if disposing is true. If disposing is false, there’s no way to safely touch a managed reference, because the object might have already been reclaimed by the garbage collector.

Executing a Windows Forms Project

Windows Forms projects are compiled just like other C# projects: you simply press Ctrl+Shift+B to build the project or choose Build Solution from the Build menu. To launch a Windows Forms project in the debugger, press F5, or choose Start from the Debug menu. If you execute the SimpleForm application, a simple form with no buttons or other controls will be displayed, as shown in Figure 11-3.

Figure 11-3.
The SimpleForm application.

One big difference between Windows Forms projects and the console applications from earlier chapters is that Windows Forms projects are easier to debug. Because Windows Forms projects are event driven—meaning that they respond to events—you’ll probably find it easy to examine the behavior of a Windows Forms application in the debugger. To do so, just set a breakpoint in a particular event handler, and you’ll be ready to go.

Adding a New Form to a Project

Most Windows Forms projects consist of multiple forms that handle various aspects of the application. In general, a new form is just a class that’s a descendant of the System.Windows.Forms.Form class.

There are two ways to add a new form class to your project: you can choose Add Windows Form from the Project menu, or you can right-click on the project name in Solution Explorer and then choose Add Windows Form from the shortcut menu. Either method will open the Add New Item dialog box, shown in Figure 11-4.

Figure 11-4.
Adding a new form with the Add New Item dialog box.

To add a new form, type a name for the class, and click Open. Visual C# .NET will create a new form class and add it to your project. Forms that are added to your project include a Dispose method, as well as the Initialize­Component method used by the Forms Designer.

Modal Forms vs. Modeless Forms

You can display a form to the user in one of two ways:

  • A modal form prevents access to any other portions of the application while the form is displayed. This type of form is useful when you’re displaying a dialog box that must be acknowledged by the user before proceeding.

  • A modeless form allows other parts of your application to be used while the modeless form is displayed. This type of form is useful for situations in which a form can be used over a long period of time.

Examples of modal forms are message boxes, dialog boxes that are used to open or save files, and dialog boxes that display error information. Modeless forms are used when interaction with an application is required, such as when displaying a child form in Microsoft Word. In most cases, a modeless form is preferred over a modal form, as it enables the user to control the flow of an application. However, when information must be acknowledged by the user or input must be supplied by the user before the execution of your application can proceed, a modal form is perfectly acceptable.

A form is displayed as either modal or modeless depending on the method that was called to display the form. To display a modeless form, use the Show method, as shown here:

Form addressForm = new AddressForm();
addressForm.Show();

As mentioned, when a form is displayed using Show, you use the Close method to destroy the form programmatically:

addressForm.Close();

Alternatively, you can use the Hide method to simply make the form invisible:

addressForm.Hide();

To display a modal form, use the ShowDialog method, as shown here:

addressForm.ShowDialog();

The call to ShowDialog doesn’t return until the dialog box has been dismissed by the user.

Determining the DialogResult Value

Modal dialog boxes supply a return value that provides a way to determine how the dialog box was dismissed. One reason you should be concerned about the return value is that the code that invoked the dialog box can easily determine whether the dialog box contains valid data, as shown here:

Form addressForm = new AddressForm();
DialogResult result = addressForm.ShowDialog();
if(result == DialogResult.OK)
{
    // Dialog box contents are valid.
}

The DialogResult return value generally indicates which button was clicked by the user to close the dialog box. The return value is taken from the DialogResult enumeration, which contains the following values:

  • Abort

  • Cancel

  • Ignore

  • No

  • None

  • OK

  • Retry

  • Yes

The return value is usually, but not always, the value of the button that was clicked by the user. For example, if the user presses Esc, a value of Dialog­Result.Cancel will be returned. As you’ll see in Chapter 12, you also can specify the DialogResult value returned by a form, regardless of the button clicked by the user.

Passing Values to Forms

Often when you’re using a form as a dialog box, you’ll need to pass information to and from the dialog box. Typically, you need to populate the dialog box with the initial information that’s displayed to the user, and later collect the user’s input after the dialog box has been dismissed.

In general, the simplest way to pass information to and from a form is to define properties that provide access to the input provided by the user. For example, the following code shows how properties can be used to pass name and address information to a dialog box that displays information to a user:

public void DisplayAddress(Address userAddress)
{
    AddressForm addressForm = new AddressForm();
    addressForm.UserName = userAddress.user;
    addressForm.StreetAddress = userAddress.StreetAddress;
    addressForm.ShowDialog();
}

Each property can be associated with a member variable that’s used to initialize dialog box controls. When the AddressForm class is used, the properties can be employed to populate the dialog box with appropriate values, as shown in the preceding example. When used with the DialogResult value returned from ShowDialog, property values can be retrieved only in cases in which the user has clicked the OK button, as shown here:

public Address GetAddressForUser(string user)
{
    Address userAddress = null;
    AddressForm addressForm = new AddressForm();
    addressForm.UserName = user;

    DialogResult result = addressForm.ShowDialog();
    if(result == DialogResult.OK)
    {
        userAddress = new Address();
        userAddress.StreetAddress = addressForm.StreetAddress;
        userAddress.City = addressForm.City;
        
    

    }
    return userAddress;
}

In Chapter 12, various controls will be used to collect input from the user. Properties enable you to easily obtain values from a form such as a dialog box. When the user attempts to close the form, you can validate input and store control values in member variables.



Part III: Programming Windows Forms