Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

CSharp Bible (2002) [eng]-1

.pdf
Скачиваний:
42
Добавлен:
16.08.2013
Размер:
4.29 Mб
Скачать

makes it easy to develop Windows desktop applications using a .NET-compatible language. This set of classes and the programming model that it supports is called WindowsForms.

In this chapter, you take a look at the basic structure of a WindowsForms application. You will see how a basic form is created and how controls are added to forms. We'll take a look at the .NET Framework classes available for use in a WindowsForms application, and we'll also take a look at some of the assembly attributes that you can use to add version and copyright information to your applications.

Understanding WindowsForms Architecture

Developing a WindowsForms application requires that you understand how the WindowsForms base classes are used with your .NET applications. This section examines the architecture of the WindowsForms class library.

All the classes that you use to build your WindowsForms applications reside in a .NET Framework namespace called System.Windows.Forms. This namespace contains all the classes that you need to build rich Windows desktop applications. These classes enable you to work with forms, buttons, edit controls, check boxes, lists, and many other user-interface elements. All of these classes are at your disposal and ready to use in your WindowsForms applications.

WindowsForms applications make use of two fundamental .NET Framework classes: the Form class, which manages the application's forms and the controls placed on the form, and the Application class, which manages the application's handling of Windows messages sent to and received from the forms in the application. Both of these classes reside in the .NET Framework's System.Windows.Forms namespace and make up the basic anatomy of a WindowsForms application.

The Form class

The System.Windows.Forms namespace includes a base class called Form. The Form class represents a form, or window, in your application. When you create a WindowsForms application in C#, you design a window class and use the Form class as the base class for your window class. Your window class inherits all the basic behavior of a window and adds the functionality you need to fit the needs of your application. All the basic window behaviors are built into the base Form class, and you inherit all of that behavior automatically if you derive your window classes from the Form class.

The Application class

Form classes define the look and feel of a window in your application, but they do not run by themselves. WindowsForms must be run within the context of an application. The System.Windows.Forms namespace includes a class called Application, which contains methods that help you manage your WindowsForms application.

The Application class contains methods that enable you to start, manage, and stop WindowsForms applications. WindowsForms respond to events initiated by the user, such as moving the mouse or pressing a key on the keyboard. Since the very early days of Windows,

the Windows desktop application architecture has been designed around the concept of a message loop.

In a standard Windows application, the main piece of code sits in a loop and receives messages from the Windows operating system. When the user moves the mouse, presses a key on the keyboard, selects a menu item, or performs any other operation that a window might want to act on, the operating system makes a note of the action and sends a message to the appropriate window, informing the window of the action. It is the responsibility of the window code to handle the message in an appropriate manner.

In the WindowsForms architecture, the basic concepts remain the same. WindowsForms applications have a piece of code that waits for user interaction messages to come from the operating system, which then routes the messages to the appropriate window. In the WindowsForms architecture, the Application class is the main code that manages this message handling, and the Forms class is the class that handles the messages sent to it by the Application class.

The Application class is sealed. You cannot derive classes from it. Its methods are static, which means that you can call its methods without having an object of the Application class available.

Creating Your First WindowsForms Application

Listing 21-1 shows a simple WindowsForms application. It represents a simple WindowsForms application that displays a single form and keeps running until the user closes the form.

Listing 21-1: The Hello, WindowsForms Application

using System.Windows.Forms;

public class SimpleHelloWorld : Form

{

public static void Main()

{

Application.Run(new SimpleHelloWorld());

}

public SimpleHelloWorld()

{

Text = "Hello, WindowsForms!";

}

}

The code in Listing 21-1 declares a class called SimpleHelloWorld. It derives from the .NET Framework Form class, which qualifies the class as a Windows Form class. The class contains a Main() method, which creates a new object of the SimpleHelloWorld class and uses that object as the parameter to a method in the Application class called Run(). The constructor of the SimpleHelloWorld class sets the inherited Text property to Hello,

WindowsForms!. This string is displayed as the caption of the form. Figure 21-1 shows what the form looks like when the code in Listing 21-1 is executed.

Figure 21-1: Listing 21-1 displays a simple form.

Compiling Your WindowsForms Application

As with console applications designed using C#, WindowsForms applications must be compiled with the C# compiler before you can execute their code. WindowsForms applications compiled with the C# compiler might behave slightly differently when they are launched, depending on how the code was compiled. At a minimum, you can use the following command line when compiling the code in Listing 21-1:

csc Listing21-1.cs

Like all C# applications, this produces an executable called Listing21-1.exe. If you run this executable from a console, the application's window appears. However, something interesting happens when you double-click the executable's icon in Windows Explorer. Launching the executable from Windows Explorer brings up two windows: a console window, which is empty, and the application's WindowsForms window. This behavior differs from most Windows applications. Most Windows applications don't bring up an empty console window when the application is launched. Why does the executable for Listing 21-1 bring up a console window and, more important, how can you get rid of it?

By default, the C# compiler generates console applications. These applications require a console window so that methods, such as Console.WriteLine(), have a console to write their messages out to. The .NET runtime interrogates the executable when it is launched, and if the executable is built as a console application, the runtime loader creates a new console window for the application. If you were to build Listing 21-1 using the default C# compiler command line, you would generate a console-based .NET application. This explains the empty console window that appears when the generated executable is run.

WindowsForms work with windows, not with consoles, and the console window is not needed for WindowsForms applications. The C# compiler supports a command-line argument

called target that you can use to specify the type of application being built. You can use this argument to tell the C# compiler that you want to build a Windows application that does not need a console. The following command line

csc /target:winexe Listing21-1.cs

instructs the C# compiler to compile the Listing21-1.cs file and use its contents to build a Windows executable that does not need a console. If you use this command line to build the code in Listing 21-1, launching the executable from within Windows Explorer brings up the application's form without also bringing up an empty console window.

Note The C# compiler accepts /t as shorthand for /target. The preceding command line can be shortened to csc /t:winexe Listing21-1.cs.

Understanding Assemblies: Adding Version Information to Your WindowsForms Applications

By default, WindowsForms applications do not carry any version information. However, you can use attributes built into the .NET Framework to add version information to your applications. These attributes take effect at the assembly level and are added to the code that the C# compiler outputs. All of these attributes are optional, but using them adds version and copyright information to your .NET binaries. Adding this information enables end users to use the Windows Explorer to right-click the application, select Properties from the context menu, and inspect your embedded attribute values. End users can inspect version and copyright information for your .NET WindowsForms applications just as they can inspect the same information from standard Win32 applications.

The classes that implement these attributes are in a .NET namespace called System.Reflection. When using these attributes, you must either reference this namespace with the using keyword or prefix the assembly names with the namespace name.

Some of the information specified in these attributes is written into the assembly's manifest, and other pieces of information are stored as a version information resource embedded in the assembly's executable. You can view the assembly's manifest through the ILDASM tool, and you can view the executable's version information resource by right-clicking the file in Windows Explorer and choosing Properties Version.

Tip You can add these attributes to any .NET code project. The version information is always available in the compiled output of your code.

In this section, you take a look at the following attributes:

AssemblyTitle, which assigns a title to the assembly

AssemblyDescription, which assigns a description to the assembly

AssemblyConfiguration, which describes options used when the assembly was built

AssemblyCompany, which assigns a company name to the assembly

AssemblyProduct, which assigns product information to the assembly

AssemblyCopyright, which assigns copyright information to the assembly

AssemblyTrademark, which assigns trademark information to the assembly

AssemblyCulture, which assigns locale information to the assembly

AssemblyVersion, which assigns a version number to the assembly

AssemblyTitle

The AssemblyTitle attribute enables you to give a title to the assembly. The attribute takes a string parameter in its constructor that specifies the title, as shown in the following example:

[assembly: AssemblyTitle("Listing 21-2")]

The assembly title isn't written to the assembly's manifest, but is available in the Description field of the compiled file's version information block.

AssemblyDescription

The AssemblyDescription attribute enables you to provide a description for the assembly. The attribute takes a string parameter in its constructor that specifies the description, as shown in the following example:

[assembly: AssemblyDescription("This executable was produced by compiling the code in Listing 21-2.")]

The assembly description is written to the assembly's manifest; it is also available in the Comments field of the compiled file's version information block.

AssemblyConfiguration

The AssemblyConfiguration attribute enables you to specify build configuration information for the assembly. For example, assembly configuration information may specify whether the assembly is built for a retail or debug configuration. The attribute takes a string parameter in its constructor that specifies the configuration information, as shown in the following example:

[assembly: AssemblyConfiguration("retail")]

The assembly description is written to the assembly's manifest, but isn't available in the compiled file's version information block.

AssemblyCompany

The AssemblyCompany attribute enables you to specify a company name to associate with the assembly. The attribute takes a string parameter in its constructor that specifies the company name, as shown in the following example:

[assembly: AssemblyCompany("John Wiley, Inc.")]

The assembly company name is written to the assembly's manifest; it is also available in the Company Name field of the compiled file's version information block.

AssemblyProduct

The AssemblyProduct attribute enables you to specify a product name to associate with the assembly. The attribute takes a string parameter in its constructor that specifies the product name, as shown in the following example:

[assembly: AssemblyProduct("C# Bible")]

The assembly product name is written to the assembly's manifest; it is also available in the Product Name field of the compiled file's version information block.

AssemblyCopyright

The AssemblyCopyright attribute enables you to specify copyright information for the assembly. The attribute takes a string parameter in its constructor that specifies the copyright information, as shown in the following example:

[assembly: AssemblyCopyright("(c) 2002 John Wiley, Inc.")]

The assembly product name is written to the assembly's manifest; it is also available in the Copyright field of the compiled file's version information block.

AssemblyTrademark

The AssemblyTrademark attribute enables you to specify trademark information for the assembly. The attribute takes a string parameter in its constructor that specifies the trademark information, as shown in the following example:

[assembly: AssemblyTrademark("Windows is a trademark of Microsoft Corporation.")]

The assembly product name is written to the assembly's manifest; it is also available in the Legal Trademarks field of the compiled file's version information block.

AssemblyCulture

The AssemblyCulture attribute enables you to specify culture information for the assembly. Culture information specifies the language and country information that the assembly uses to do its work. The attribute takes a string parameter in its constructor that specifies the culture information, as shown in the following example:

[assembly: AssemblyCulture("us-en")]

Culture strings are defined by an Internet standard called RFC1766. The standard is titled Tags for the Identification of Languages and is available on the Internet at www.ietf.org/rfc/rfc1766.txt. The assembly product name is written to the assembly's manifest; it is also available in the Legal Trademarks field of the compiled file's version information block.

Note Culture information can be added only to libraries and modules. Culture information cannot be added to executables, because executables cannot be localized. Only librarybased assemblies can be localized. If you try to add the AssemblyCulture attribute to a code base that is compiled into an executable target, the C# compiler issues the

following error message:

error CS0647: Error emitting 'System.Reflection.AssemblyCultureAttribute' attribute - - 'Executables cannot be localized, Culture should always be empty'

The assembly description is written to the assembly's manifest, but isn't available in the compiled file's version information block.

AssemblyVersion

The AssemblyVersion attribute enables you to assign a version number to your assembly. Version numbers in .NET come in four parts:

A major version number

A minor version number

A revision number

A build number

Each of these parts is separated by a period. The attribute takes a string parameter in its constructor that specifies the version number, as shown in the following example:

[assembly: AssemblyVersion("1.0.0.0")]

You must always specify a version number. If you specify a major and a minor version number, you can let the C# compiler autogenerate the other numbers when the code is built. You may want to do this if you want each build of your code to have a unique version number. By using the asterisk character for a build number, the C# compiler automatically assigns one. The generated build number is equal to the number of days since January 1, 2000, as shown in the following example:

[assembly: AssemblyVersion("1.0.0.*")]

This example gives the assembly a major version of 1, a minor version of 0, a revision number of 0, and a build number automatically assigned by the C# compiler.

If you use an asterisk for a revision number, the C# compiler automatically assigns a revision number and a build number. The generated revision number is equal to the number of seconds since midnight local time, modulo 2. The generated build number is equal to the number of days since January 1, 2000, as shown in the following example:

[assembly: AssemblyVersion("1.0.*")]

This example gives the assembly a major version of 1, a minor version of 0, and revision numbers and build numbers automatically assigned by the C# compiler.

The assembly product name is written to the assembly's manifest; it is also available in the Assembly Version, Product Version, and File Version fields of the compiled file's version information block.

Listing 21-2 adds assembly version attributes to the code in Listing 21-1.

Listing 21-2: Simple Windows Form Application with Version Information

using System.Reflection; using System.Windows.Forms;

[assembly: AssemblyTitle("Listing 21-2")]

[assembly: AssemblyDescription("This executable was produced by compiling the code in Listing 21-2.")]

[assembly: AssemblyConfiguration("Retail")] [assembly: AssemblyCompany("John Wiley, Inc.")] [assembly: AssemblyProduct("C# Bible")]

[assembly: AssemblyCopyright("(c) 2002 John Wiley, Inc.")] [assembly: AssemblyVersion("1.0.*")]

public class SimpleHelloWorld : Form

{

public static void Main()

{

Application.Run(new SimpleHelloWorld());

}

public SimpleHelloWorld()

{

Text = "Hello, WindowsForms!";

}

}

Taking a Closer Look at the Application Object

The Application object contains properties, methods, and events that you can use in your WindowsForms code. In this section, you take a look at the class members that you'll use most often.

Understanding Application events

The Application class supports four events that you can handle in your WindowsForms applications:

The ApplicationExit event is fired when the application is about to shut down. Delegates of type EventHandler can be assigned to this event. The EventHandler delegate is defined in the .NET System namespace. The delegate takes two parameters: an object that references the object sending the event and an EventArgs object specifying event arguments. It does not return any value.

The Idle event is fired when the application finishes dispatching messages from the operating system and is about to enter the idle state. The application leaves the idle state when it determines that more messages need to be processed. Delegates of type EventHandler can be assigned to this event. The EventHandler delegate is defined in the .NET System namespace. The delegate takes two parameters, an object that references the object sending the event, and an EventArgs object specifying event arguments. It does not return any value.

The ThreadException event is fired when an untrapped thread exception is thrown. Delegates of type ThreadExecptionEventHandler can be assigned to this event. The

ThreadExecptionEventHandler delegate is defined in the .NET System.Threading namespace. The delegate takes two parameters: an object that references the object sending the event and a ThreadingExceptionEventArgs object specifying event arguments. It does not return any value.

The ThreadExit event fires when a thread is about to shut down. When the main thread for an application is about to be shut down, this event is raised first, followed by an ApplicationExit event. Delegates of type EventHandler can be assigned to this event. The EventHandler delegate is defined in the .NET System namespace. The delegate takes two parameters: an object that references the object sending the event and an EventArgs object specifying event arguments. It does not return any value.

Working with events in code

The code in Listing 21-3 adds to the form code in Listing 21-2 by handling events from the Application object.

Listing 21-3: Handling Application Events

using System;

using System.Threading; using System.Reflection; using System.Windows.Forms;

[assembly: AssemblyTitle("Listing 21-3")]

[assembly: AssemblyDescription("This executable was produced by compiling the code in Listing 21-3.")]

[assembly: AssemblyCompany("John Wiley, Inc.")] [assembly: AssemblyProduct("C# Bible")]

[assembly: AssemblyCopyright("(c) 2002 John Wiley, Inc.")] [assembly: AssemblyVersion("1.0.*")]

public class HelloWorldForm : Form

{

public HelloWorldForm()

{

Text = "Hello, WindowsForms!";

}

}

public class ApplicationEventHandlerClass

{

public void OnApplicationExit(object sender, EventArgs e)

{

try

{

Console.WriteLine("The application is shutting down.");

}

catch(NotSupportedException)

{

}

}

public void OnIdle(object sender, EventArgs e)

{

Console.WriteLine("The application is idle.");

}

public void OnThreadException(object sender, ThreadExceptionEventArgs

e)

{

Console.WriteLine("an exception thrown from an application thread was caught!");

}

public void OnThreadExit(object sender, EventArgs e)

{

Console.WriteLine("The application's main thread is shutting down.");

}

}

public class MainClass

{

public static void Main()

{

HelloWorldForm FormObject = new HelloWorldForm(); ApplicationEventHandlerClass AppEvents = new

ApplicationEventHandlerClass();

Application.ApplicationExit += new EventHandler(AppEvents.OnApplicationExit);

Application.Idle += new EventHandler(AppEvents.OnIdle); Application.ThreadException += new

ThreadExceptionEventHandler(AppEvents.OnThreadException); Application.ThreadExit += new

EventHandler(AppEvents.OnThreadExit);

Application.Run(FormObject);

}

}

The new class in Listing 21-3 is called ApplicationEventHandlerClass and contains methods that handle the events fired from the Application object. The Main() method creates an object of the ApplicationEventHandlerClass and adds its code to the Application class's list of event handlers.

The event handlers in the ApplicationEventHandlerClass write to the console. This is perfectly legal, even in a WindowsForms application. If you compile the code in Listing 21-3 using the console executable target (csc /target:exe Listing21-3.cs), the event handler messages are written to the console window that is used to start the application. If you compile the code in Listing 21-3 using the Windows executable target (csc /target:winexe Listing21-3.cs), no console is associated with the process and the console messages aren't displayed.

Understanding Application properties

The Application class supports several properties that you can use in your C# applications. The following sections describe how to use each of these properties.

AllowQuit

Соседние файлы в предмете Программирование на C++