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

C# Bible - Jeff Ferguson, Brian Patterson, Jason Beres

.pdf
Скачиваний:
64
Добавлен:
24.05.2014
Размер:
4.21 Mб
Скачать

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

The Boolean AllowQuit property specifies whether your code can programmatically end the application. The property returns True if your code can instruct the application to exit and False otherwise. This property is read-only and cannot be set. Ordinarily, users can end applications by closing the application's main form. Some applications are hosted in containers, such as Web browsers, and those applications cannot be programmatically ended. They exit only when their container closes. If the AllowQuit property returns true, you can call an Application method called Exit() to programmatically end the application. You examine the methods of the Application object in the section titled "Understanding Application Methods."

CommonAppDataRegistry

The CommonAppDataRegistry property returns a reference to an object of class RegistryKey. The returned RegistryKey object references a key in the Registry that the application can use to store Registry data that should be available to all users of the application. This property is read-only and cannot be set.

The RegistryKey class is a part of the .NET Framework and is available in a namespace called Microsoft.Win32. It represents a specific key in the Registry and contains methods that enable you to create subkeys, read values, and perform other work related to Registry keys.

CommonAppDataPath

The string CommonAppDataPath property references a path on the file system that the application can use to store file-based data that should be available to all users of the application. This property is read-only and cannot be set.

The application data path is stored beneath the Windows documents folder path used for all users, which is usually a path such as C:\Documents and Settings\All Users\Application Data. The actual application path points to a folder beneath this "all users" document path having the form CompanyName\ ProductName\ ProductVersion. The CompanyName, ProductName, and ProductVersion folder names are based on the values of the application properties of the same name. If you do not set these properties, the Application class provides reasonable defaults. The code in Listing 21-1, for example, has a common application data path of C:\Documents and Settings\All Users\Application Data\SimpleHelloWorld\SimpleHelloWorld\V0.0. If the code in Listing 21-1 were to set the Application class's CompanyName, ProductName, or ProductVersion properties, the folder names in the common application data path would change to reflect the values of those properties.

The product version folder path uses only the major and minor version numbers specified in your application, regardless of the number of values you set in your application's [AssemblyVersion] attribute. If your application uses an [AssemblyVersion] attribute with a value of 1.2.3.4, for example, the version number portion of the common application data path will be 1.2. The letter V always prefixes your application's major version number in the version number portion of the data path.

CompanyName

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