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

Visual CSharp .NET Developer's Handbook (2002) [eng]

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

Overview

With all of the emphasis on distributed applications that only appear on the Internet, it's easy to forget that not every application ever created appears on someone's website. Distributed application development is extremely important—we'll spend a considerable part of this book discussing that topic. However, the desktop application hasn't gone away and it's unlikely to go away in the near future. The simple fact is that desktop applications serve the needs of many computer users who don't need access to the Internet, much less access to a business partner's network.

You can create a vast assortment of application types with C#, including desktop applications. We've already looked at a simple example of a desktop application in Chapters 3 and 4 (Parameters and CommandLine2). This chapter is going to build on your knowledge of desktop applications and show you how to create several application types including dialogbased, single document interface (SDI), and multiple document interface (MDI).

Desktop Application Types

Desktop applications come in a variety of shapes and sizes. C# is quite capable of creating any application you can imagine (and perhaps a few that you can't). However, there are five application types that exemplify desktop applications as a whole, and that's what we'll concentrate on first.

Console applications Represent those situations when you don't need a full-fledged interface for the user to work with. Many console applications appear as part of script, task scheduler, or remote machine access applications.

Dialog-based applications Are normally reserved for utilities or applications that are too small to require complete menuing systems. Many dialog-based applications provide informational displays, and they're known for their small memory footprint.

Single-document applications Are representative of simple applications that work with their own data, like note takers or small database front ends. These applications also require a menuing system of some type. A single-document application works with one document at a time.

Multiple-document applications Include full-fledged applications like word processors and spreadsheets. When you think about it, they represent that fringe area of C# programming where you need to weigh the flexibility of C# against the development speed offered by RAD programming environments like Visual Basic. Multiple-document applications can work with more than one document at a time and could work with multiple document types simultaneously.

HTML-based applications Work with data of some type (like single-document or multipledocument applications) but with browser twist. Instead of a standard editor, your user will see what amounts to a web browser front end. The data normally appears formatted as a web page.

Note Remember that we're talking about desktop applications in this chapter. C# is capable of creating all kinds of different code. You can use it to create DLLs, ActiveX controls,

components, background executing programs like screensavers, and even extensions to C# itself. We're only talking about general applications in this chapter, but we'll cover many of these other possibilities as the book progresses. Two notable exceptions from the C# repertoire include ISAPI Extensions and device drivers.

Console

I made some statements previously that gave you an overall sense of what a console application is, but they were too sweeping to really tell you what a console application is all about. A console application has a DOS window look rather than the more familiar Windowsstyle appearance. It uses monospaced font, just like you'd see in a DOS window, and you can use special input/output functions such as Console.WriteLine() and Console.Read(). However, internally, the program is a Windows application.

One of the early reasons for using console applications was to move a utility from DOS to Windows. Developers and network administrators owned a wealth of management applications that worked well at the command prompt. The high end user didn't require a user interface and appreciated the efficiency boost that a console application could provide. Working at the command line is still a major part of the network administration experience, but many network administrators are moving from the command line to large windowed management applications such as the Microsoft Management Console (MMC).

Tip Interestingly enough, some developers are still moving their DOS utilities to Windows. It's safe to assume that you'll be able to move the "business logic" of your DOS application to Windows using a console application. You may also be able to move some of the display and printing elements. However, it's never safe to assume that you'll be able to maintain one set of code for both DOS and Windows by using a console application— the two environments are different enough that you'll always have to make changes in the move from DOS to Windows.

Today, console applications serve a different purpose. Network administrators commonly look to console applications as a means to automate maintenance tasks. A console application is a perfect solution for scripting and task scheduling. Because a console application doesn't require a GUI interface, a network administrator can use it across a network connection from a command prompt. Console applications also support pipes and other means of redirecting output to a file. In fact, the console application is so important in this role that Microsoft actually added more command-line tools to Windows XP for the sole purpose of network and system management.

Console applications serve other purposes as well. For example, many user-level utilities either support a command-line interface or use a console interface. Many developers use console applications for experimentation. Console applications offer a clarity of coding that's often obscured by the GUI code in a Windows application.

Standard Windows

The standard Windows format is still the main method for creating desktop applications. Windows applications typically come in three styles: dialog-based, SDI, and MDI. Each of these styles serves a different purpose. A developer won't want to suffer the encumbrance of an MDI application when a dialog-based application will do. On the other hand, a dialog-

based application is ill suited to present large quantities of textual or graphic information. You need an SDI or MDI application to perform most types of large-scale data manipulation.

Many programming languages differentiate between the various Windows application types. For example, Visual C++ has separate wizard settings for each type of application. C# doesn't provide a real differentiation between the three types of Windows application—every application begins as a dialog-based application. The presentation of the information and use of controls changes the application type. For example, the CommandLine2 application in Chapter 4 began as a dialog-based application, but the addition of a RichTextEdit control and a menu changed the application's appearance to the SDI model. The following sections describe the uses for the various Windows application types, as well as presentation concerns that you need to consider as you develop the application.

Dialog-Based Applications

Many people associate dialogs with configuration screens, About boxes, and other adjuncts to a full-fledged application. Dialog-based applications have a place, too. They're extremely useful for utility-type applications where you need to display a fairly minimal amount of data and you require minimal user input. The main advantages of using a dialog-based application include:

Quick prototyping

Short development cycle

Small memory footprint

Tip When deciding whether to build a dialog-based or window-based application, think utility. If your application fits into the utility category, it's probably a good candidate for a dialog-based interface. On the other hand, if you're thinking about adding a lot of features or allowing the user to interact with the application heavily, you may want to look at an SDI or MDI application. Make sure you take future expansion into account when making your decision—a bad choice today could cost you a lot in rework time tomorrow.

So, what makes a dialog-based application better than a full-fledged window-based application? One of the more important factors is size. You can create two versions of the same application, one that uses a dialog front end and another that depends on a window. The dialog version will be smaller every time. In addition to conserving resources, you may find that the dialog version loads faster. A dialog-based application is simply more efficient than its window-based counterpart.

You may find that building a dialog-based application is faster as well. Dialog-based applications are meant to be small and efficient. If you find that you're adding a lot of bells and whistles to this kind of application, perhaps you've used the wrong kind of application to start with. Dialog-based applications normally eschew menus and other paraphernalia that a window-based application requires in order to provide a user-friendly front end. Fewer bells and whistles spell reduced development and debugging time for the programmer. Obviously, anything that speeds the programmer along is worth looking at.

The only real problem with dialog-based applications is that some programmers feel they can stuff one to the point of breaking. I've seen some dialog-based applications that are so filled with gizmos that you really can't tell what they're supposed to do. While a dialog-based

application may look a little more cramped than its SDI or MDI counterpart, you shouldn't have it so crammed that no one can use it.

Tip You can reduce clutter on a dialog-based application by using tabbed pages, just like a property dialog used by Windows for configuration purposes. Each tab should have a specific purpose, and you should limit the number of tabs to those that can fit comfortably in the default dialog frame.

Single Document Interface (SDI)

A single-document application is one like Notepad or Microsoft Paint. It's designed to handle one document at a time, which reduces programming complexity and the amount of resources required for running the application. You'd use this kind of windowed application for something small, like a text editor or perhaps a small graphics editor. A single-document application allows users to interact fully with the document that you want them to create, but it's usually less robust than an application designed to work with multiple documents. In addition, the single-document application usually has a minimum of one less menu than a multiple-document application would—the Window menu that's used to select the document you want to edit.

SDI applications also use controls that tend to support object linking and embedding (OLE). For example, the RichTextEdit control offers modes that support use of the control as an OLE container. An OLE container can act as a receptacle for data from other applications. For example, OLE enables a user to place a graphic image within a text document. Unlike some Visual Studio languages, you'll find that you need to develop OLE server capabilities in C# through manual programming techniques—none of the wizards offer to set this feature up for you.

Unfortunately, single-document window-based applications can suffer from the same problem as a dialog-based application—too much complexity. I still remember problems trying to use older versions of Corel Draw. Every time I wanted to look at a drawing, I had to close the currently open document before doing so. This limitation made Corel Draw a little harder to use than it needed to be. For example, I wasted a lot of time trying to compare one drawing against another. (Fortunately, Corel Corporation has corrected this oversight in current versions of Corel Draw.)

Tip The single-document, window-based application works surprisingly well when it comes to database management systems. The reason is fairly simple. Very few (if any) of your users will need to open more than one database at a time. Even if they do, the rules for working with databases would make it less desirable to allow the user to access multiple databases by themselves. You'll normally want to control all access to the various database elements programmatically and display the results to the user.

Multiple Document Interface (MDI)

Now we're down to the multiple-document application. You'd use this kind of window-based application to create something like a word processor or spreadsheet application. If you think about it for a second, a text editor has a limited appeal simply because it can only open one document at a time. People need to be able to compare one document to another; that's why multiple-document applications aren't only nice, but required in so many situations.

Multiple-document applications also tend to be feature rich. (You can still go overboard; just look at all the people complaining about the bloated feature sets of major products produced by vendors today.) A text editor may provide a very simple find function and not offer any means for replacing occurrences of text. A full-fledged word processor provides both search and replace as standard features.

The failings of a multiple-document application begin with the fact that it can handle multiple documents. The capability of handling more than one document at a time means a lot of additional programming. You don't just have to keep track of all the open documents. There's the Window menu to manage, and special program features like split-screen to consider as well. You'll also need to decide whether the user will be allowed to display more than one document at once. Things like minimizing one document while keeping another maximized require additional code as well. In sum, you'll need to be prepared for some major programming time before you even start a multiple-document application.

Of course, multiple-document applications have plenty of other disadvantages as well. For example, if you've ever tried to use Word for an OLE server, you know all about the frustration of waiting for this behemoth application to open every time you click on a link in another application. You've probably experienced the serious consequences of running out of memory as well. Until recently, every time you wanted to use OLE, you had to have enough memory to run both applications (the client and the server). Fortunately, Microsoft has reduced this requirement somewhat by allowing the server to take over the client's window; now the server only has to worry about working with the document itself. The client window provides a framework for the server's menus and toolbar, so there isn't any extra memory wasted.

Web-Based Applications

Web-based applications are becoming more popular as more companies require distributed application support. Combining a web page front end with data delivered using SOAP or some other XML technology makes sense in a world where developers don't even know what platform will run the application. However, before you begin thinking that a browser is the only way to create a Web-based application, consider the fact that Visual Studio supports other types of web-based application development, some of which are completely invisible to the end user. For example, the help files provided with Visual Studio .NET rely on web technology, but the interface looks like a typical desktop application. The first clue that Visual Studio .NET is using an HTML-based front end is when you need something found on Microsoft's website and the application looks for an Internet connection.

Tip You'll find Microsoft Help URLs placed throughout the book. All of these URLs begin with ms-help://. You can enter the URL in the Address Bar for Visual Studio Help, or you can open a copy of Internet Explorer and enter the URL there. One of the benefits of using Internet Explorer is that you can see an unencumbered view of the information. Of course, you lose the ability to search the rest of Visual Studio .NET Help when using Internet Explorer as your browser. However, you'll find the loss of search capability minimal when viewing lists of information, such as the list of WMI hardware classes discussed in the "Script-Based Example for Batch Jobs" section of the chapter.

From a development perspective, you can divide web-based applications into two categories: those that rely on a browser and those that use an HTML-based front end. The browser

application is more flexible because you can place it on any machine with a compatible browser. For example, it's possible to develop SOAP applications on your desktop machine that will ultimately run on a PDA using the browser application. The HTML-based front end has the advantage of functionality. You can combine standard desktop elements with HTML elements to create a type of hybrid application.

So, what good is an HTML-based document application? Think about the advantages of creating your own custom web browser. You could set it to view the company website automatically and restrict users from viewing non-business-oriented sites on the Web. Since a custom browser need not carry all of the generic features of a full-fledged browser, it would consume less memory and less disk space as well. In other words, you could create an environment that provides all of the functionality of a browser with none of the problems (at least from a company website access perspective).

However, this new application type is more valuable than you may initially think. For example, you could add HTML-enabled components to an existing application to allow it to access a web server–based help desk. Instead of creating a standard help file and adding it to your application, you can create a very specialized Web browser and add it instead. (This is precisely the route that Microsoft took with Visual Studio .NET.)

The advantages of HTML-based help are clear. Using the older help files meant that you couldn't easily update the help files for your application once you sent the application to a customer or distributed it throughout the company. Updating HTML help is as easy as changing a file on your web server. In addition, working with Microsoft Help Workshop isn't easy—many developers found deciphering the arcane language used in help files akin to learning a new programming language. HTML-based help requires no compiler or special tools, just a text editor. (Theoretically, you'll want an editor designed to work with HTML before writing a huge help file.)

There are disadvantages to HTML help as well. For one thing, it's a lot of more difficult to build adequate search capability into HTML-based help. Since finding the information the user wants is just as important as creating it in the first place, HTML-based help may not be the answer of choice for novice users. In addition, HTML-based help necessitates an Internet (or, at least, an intranet) connection. If your company has many users on the road, trying to find an Internet connection may not be practical. Of course, you could always create a local copy of the required HTML files, but that would create the same problem as you had before— out-of-date help files.

Writing Console Applications

As previously mentioned, console applications are useful for a number of tasks, so knowing how to create a console application is important. Most of the applications so far have relied on a dialog-based presentation because the dialog presentation is good for shorter example code. The following sections show how to create two examples that you could use to work with your machine from the command prompt. The goal is to create applications that can execute in the foreground, as part of a script, as a scheduled task, or even as part of another application.

Simple Example

You can create new console applications by selecting the Console Application project in the New Project dialog box shown in Figure 5.1. The resulting project is bare. It includes only a namespace and class declaration with an empty Main() method. As previously mentioned, console applications are designed to provide their functionality with a minimum of memory and resource usage.

Figure 5.1: The New Project dialog box contains a special icon for console applications.

Console applications generally eschew graphics of any kind. In fact, console applications can access the System.Console class for all input and output requirements. For example, if you want to output some text to the command prompt display, you could use either of these two methods:

Console.WriteLine("Method 1");

Console.Out.WriteLine("Method 2");

The first method will always output the string to the screen. The output destination of the second method depends on where you set the application output. While the default setting uses the console screen, you can use the Console.SetOut() method to select another location, such as a file. You can also use the techniques for the Diagnose example in Chapter 2 to output messages to the event logs. This is a favorite technique for console applications designed to run as part of a script or of the Task Scheduler on a server.

Part of writing a console application is to know how to process the environmental data. You don't worry about this information in a standard Windows application as much because the application isn't running at the command line. Listing 5.1 shows a simple example of reading all of the environment variables on the current machine and sending them to the console display. (You can also find this code in the \Chapter 05\SimpleConsole folder on the CD.)

Listing 5.1: Processing the Environment Variables

using System;

using System.Diagnostics;

namespace SimpleConsole

{

class CheckEnvironment

{

[STAThread]

static void Main(string[] args)

{

int

Counter;

//

Loop counter.

bool

NoPause = false;

//

Should the application pause?

//Determine if the user asked for help. if (args.Length > 0)

for (Counter = 0; Counter < args.Length; Counter++) if (args[Counter] == "/?")

{

Console.WriteLine("Displays system environment " + "variables.");

Console.WriteLine("Use the /NoPause switch to " + "display without a pause.");

return;

}

//Create an instance of the process information. ProcessStartInfo MyInfo = new ProcessStartInfo();

//Process each environment variable.

foreach(String Key in MyInfo.EnvironmentVariables.Keys)

{

// Write the current key and key value. Console.WriteLine("The current key is: {0}", Key); Console.WriteLine(MyInfo.EnvironmentVariables[Key]); Console.WriteLine();

}

//Determine if we need to pause. if (args.Length > 0)

for (Counter = 0; Counter < args.Length; Counter++) if (args[Counter].ToUpper() == "/NOPAUSE")

NoPause = true;

//Only needed so application pauses.

if (!NoPause)

{

Console.Write("Press any key when ready..."); Console.ReadLine();

}

}

}

}

The code begins by checking for the /? command-line switch. Any console application you write should include at least a modicum of help for those who want to use it. Generally, you'll want to include a short description of application function and any command-line switches.

After checking for the /? command-line switch, the code creates a new ProcessStartInfo object, MyInfo object. This object contains a wealth of information about the application's starting environment, including the environment variables. You access the environment variables using MyInfo.EnvironmentVariables[]. The index is a string containing the name of the key.

The only problem with using the MyInfo.EnvironmentVariables[] index is that you don't know the key names when the application starts because every machine can have a different set of environment variables. That's where the foreach loop comes in handy. This loop accesses the MyInfo.EnvironmentVariables.Keys collection, which contains the name of every key defined on the user's machine. C# excels at working with collections using the technique shown in Listing 5.1.

The application ends by checking for the /NoPause command-line switch. Notice the use of the ToUpper() method to ensure the code finds the switch in the args list no matter how the user capitalizes the switch. The NoPause variable determines if the application exits directly or pauses for user input. The addition of a pause enables the user to access the application from within Windows or from the command prompt with equal ease.

This is actually a handy maintenance utility to have around because you can use the Task Scheduler to output the user's environment to a known location on the server using redirection like this:

SimpleConsole /NoPause >> Temp.txt

Some applications insist on adding environment variables to the system and then don't remove them later. As the system gets more clogged with weird environment entries, it can slow. In some cases, a bad environment string can also cause some applications to fail (or, at least, not behave very well). It's also helpful to have an application parse the environment variables looking for development needs. For example, a simple script could detect the presence of path entries for the .NET environment and provide you with a simple "Ready" or "Not Ready" indicator of system setup.

Script-Based Example for Batch Jobs

Many console applications begin and end their existence at the command line because the developer doesn't need them for any other purpose. However, as network administrators begin to write more script applications, the need for console applications that can perform some type of generic low-level work increases. The console application becomes a "black box" that accepts some input from the network administrator, then provides a single output in the form of a return value. Often, the return value indicates only success or failure, but it can offer more.

The example in this section accepts a Windows Management Instrumentation (WMI) query and a text filename as input. The application outputs selected data about the query to a text file. The return value of the application is the number of devices of the requested type. If the application returns 0, then none of the requested devices exists and the text file is blank. Listing 5.2 shows the source code for this example.

Listing 5.2: WMI Provides an Interesting Basis for a Console Application

 

 

 

static int Main(string[] args)

 

 

{

Counter;

// Loop Counter

int

ManagementObjectSearcher

MOS;

// WMI Query Object

ManagementObjectCollection

MOCollect;

// Query Result Collection.

string

Query;

// Query Request String

TextWriter

SendOut;

// Output File Object.

bool

Verbose;

// Output to file and screen.

bool

Clear;

// Clear the old output file.

string

OutFile;

// Output Filename

//Verify the user has provided input. if (args.Length == 0)

{

Console.WriteLine("You must supply a query or request" + "help using the /? switch.");

return 1;

}

//Handle help requests.

if (args.Length > 0)

for (Counter = 0; Counter < args.Length; Counter++) if (args[Counter] == "/?")

{

Console.WriteLine("Displays system information " + "using Windows Management Instrumentation (WMI).");

Console.WriteLine(); Console.WriteLine("Command Line:");

Console.WriteLine("\tConsoleScript /Query:<Query> " + "/Out:<Filename> [/V] [/Clear]");

Console.WriteLine(); Console.WriteLine("/Query:<Query>\tProvide a query " +

"string as input.");

Console.WriteLine("\t\tAn example query would be, \"" + "SELECT * FROM Win32_LogicalDisk\"");

Console.WriteLine("/Out:<Filename>\tName of the " + "file you want to use for output.");

Console.WriteLine("/V\t\tDisplays the output on " + "screen as well as outputting to the\r\n\t\tfile.");

Console.WriteLine("/Clear\t\tClear the output file " + "before writing to it.\r\n\r\n");

Console.WriteLine("Return values:"); Console.WriteLine("\t0 - Success"); Console.WriteLine("\t1 - No Input Provided"); Console.WriteLine("\t2 - No Query Found"); Console.WriteLine("\t3 - Device Access Error"); return 0;

}

// Locate the query.

for (Counter = 0; Counter < args.Length; Counter++) if (args[Counter].Length > 7)

{

if (args[Counter].Substring(0, 7).ToUpper() == "/QUERY:") break;

}

else

if (Counter == args.Length - 1)

{

Console.WriteLine("No Query Found"); return 2;

}

// Place the query in a string.

Query = args[Counter].Substring(7) + " "; Counter++;

while (args[Counter].Substring(0 , 1) != "/")