Help and Application-Embedded Support

Overview

Help: Is it the final polish on a professional application or a time-consuming chore? It all depends on the audience, but most commercial applications need a support center where users can seek assistance when they become confused or disoriented. Without this basic aid, you (or your organization's technical support department) are sure to be buried under an avalanche of support calls.

In this chapter, you learn:

 
Chapter 14 - Help and Application-Embedded Support
 
byMatthew MacDonald  
Apress 2002
Companion Web Site
 

The Case for Help

In recent years there has been a shift away from printed documentation. The occasional weighty manual (like the book you're holding now) is still required for learning advanced tools, but the average piece of office productivity or business software no longer assumes the user is willing to perform any additional reading. Instead, these programs are heavily dependent on natural, instinctive interfaces, and use online Help to patch the gaps and answer the occasional user question.

Online Help doesn't have to take the form of a second-rate user manual, however. The advantages of online Help are remarkable:

  • Increased control. With a little effort, you can determine exactly what information users see when they click the F1 key. With a printed book, users might look for information using the index, table of contents, or even a third-party "…For Dummies" guide, and you have no way of knowing what they will find.
  • Rich media. With online Help you can use as many pictures as you want, in any combination, and even include sounds, movies, and animated demonstrations.
  • Search tools and context-sensitivity. Help systems can automate most of the drudgery associated with finding information. They can look for keywords with a full-text search (rather than relying on a human-compiled index), and programs can use context-sensitivity to make sure users see the appropriate topic immediately.

All help standards provide these advantages in one form or another. In the next section, you explore the Help landscape.

 
Chapter 14 - Help and Application-Embedded Support
 
byMatthew MacDonald  
Apress 2002
Companion Web Site
 

Types of Help

Standardized Help has existed since the Windows platform was created, and even in the DOS world in little known tools like QuickHelp. Throughout the years (and versions of Windows), Help has continued to evolve, passing through several distinct stages, which are described in the next few sections.

WinHelp

The WinHelp format used in Windows 3.0 still exists, and can be used in the most modern Windows application. Unfortunately, it looks irredeemably garish. Help files from different authors tended to look—and act—differently.

Figure 14-1: WinHelp: a piece of living history

WinHelp 95

When Windows 95 was introduced, a new standard (often referred to as WinHelp 95) took over. WinHelp 95 files are familiar to almost any computer user, and they are still used in countless programs.

WinHelp 95 was a major improvement in the Help world. Whereas the original WinHelp forced developers to create their own contents page with hyperlinks, WinHelp 95 files use a separate contents file (with the extension .cnt) to define the standardized multilevel table of contents. WinHelp 95 really has two parts: the .cnt contents page (which also provides a standardized index and full-text search), and the .hlp help file that provides the actual topics. When a user double-clicks a topic, the table of contents disappears, and is replaced with the appropriate help window.

Figure 14-2: WinHelp 95: a facelift

The standardized table of contents was both the most significant advance and the most obvious limitation of WinHelp 95. The obvious problem is that users often need to jump back and forth between the table of contents and the topic pages before they find the content they need. This process is tedious, and it feels complicated because there can be multiple windows scattered about the desktop.

HTML Help

The next version of WinHelp was named HTML Help, because the source files were written in HTML markup language instead of the RTF format. HTML Help debuted with Windows 98 and also shipped with Internet Explorer 4. A common source of confusion about HTML Help is the idea that it is somehow supposed to provide help over the Web or browser-integrated help. While HTML Help depends on some components that are also used in Internet Explorer, it really has little to do with the Internet. Instead, HTML Help is an improvement to WinHelp that combines the table of contents and topic views in the same window (see Figure 14-3).

Figure 14-3: HTML Help: the industrial revolution of help

The new HTML Help view makes it dramatically easier to browse through a long, multilevel table of contents without losing your place. By dividing and subdividing information into its smallest bits, Help developers are able to put fairly lengthy, complex content in a help file. With HTML Help, developers also started to use DHTML and JavaScript text directly in their Help to create collapsible headings and other neat tricks. In some cases (for example, the Visual Studio 6 documentation and the SQL Server documentation), Microsoft refers to these help files as "books online." HTML Help files always use the .chm extension.

MS Help 2

The next revolution to the Help world is tentatively titled MS Help 2, and it's the help engine used by Microsoft's MSDN help in Visual Studio .NET. The first Help 2 engine ships with Visual Studio .NET, but it isn't yet supported by most third-party tools, and there isn't a great deal of information about it (some basic information is available at http://helpware.net). Help 2 promises some long-awaited improvements to HTML help, like a redesigned user interface, and the ability to embed a help window in an application interface with minimum fuss. However, it also has its idiosyncrasies. For example, every Help 2 file must be registered with the Windows operating system. You can't simply copy the appropriate .HxS file to another computer.

Figure 14-4: Help 2: a new standard?

  Note 

One of the exciting features with MS Help 2 is that it can plug into the Visual Studio .NET Help collection. That means that tool vendors can distribute Help with their components that will pop into the Dynamic Help window in the Visual Studio .NET IDE when the component is being used.

Some Help Authoring Tools

Microsoft provides only rudimentary tools for compiling source files to create Help systems. To have the full range of tools for designing, linking, and configuring your Help, you will probably need to turn to a third-party design tool. Creating Help is beyond the scope of this book, but there are a few starting points:

  • The "professional" Help design systems tend to ship with countless tools—and intimidating prices. Two leading examples are RoboHelp (http://www.ehelp.com) and ForeFrontHelpCenter (http://www.componentone.com/ffhelp/ff.htm), although numerous other mutually incompatible design tools are available.
  • Some Help systems are designed from the ground up with single-sourcing in mind, with varied degrees of success. Doc-to-Help (http://www.wextech.com) attempts to integrate printed documents in Microsoft Word with Help, and WebWorks Publisher (http://www.quadralay.com) works magic with FrameMaker files—at the cost of forcing you to learn and use a proprietary language.
  • Numerous smaller-scale utilities assist with the compilation or some aspects of development (like creating a table of contents) but don't assume you'll use an HTML editor or other tool to write the actual content. An example of a program like this is FAR (http://www.helpware.net), which is unique in being one of the first third-party tools to introduce support for MS Help 2. You can also find many cheaper Help tools at shareware sites online.
 
Chapter 14 - Help and Application-Embedded Support
 
byMatthew MacDonald  
Apress 2002
Companion Web Site
 

Classic Bad Help

Have you ever had this experience? You find an unusual option buried deep in an application, and it piques your curiosity. You hit F1, curious to find out what this option accomplishes. But your optimism dwindles when you read the description provided by the context-sensitive Help system: "To enable option X, click once on the option X check box. To disable option X, click the option X check box again to remove the check mark. Click OK to save your changes."

Clearly something is missing here. You want to know what option X does; the Help wants to explain, in oddly explicit detail, how to use a check box. The situation is ridiculous, as the function of option X is not at all obvious, but the way to use a check box is an instinctive part of every computer user's understanding. If you don't know how to use a check box, you probably wouldn't have guessed to press the F1 key for help.

This is a classic example of bad help. Some of the characteristics of bad Help include:

  • It describes the user interface. Users don't need to know how the interface works-they will often discover that by trial and error. They need to know what it does.
  • It's long. Even HTML Help doesn't have the same bandwidth as a printed document, and endless scrolling is sure to frustrate users.
  • It uses visual clues. Instructing the user to look at the "top left" or "middle right" may seem logical enough, but with the application running in another (potentially minimized) window, it can cause confusion.
  • It omits information. Printed documents can afford to choose what they cover. However, Help documents are shipped with the software, and expected to provide a matching reference. Thus, you can't ignore any option or setting that's in the interface.

To understand good help, you need to recognize that most Help is designed to provide reference information. Help really shines compared to a printed book when it's able to use context sensitivity to automatically display a piece of information about a specific window or setting. This is the type of information that all users need occasionally while working with an application they mostly understand.

On the other hand, Help is relatively poor at providing tutorial-based learning, which explains tasks that incorporate many different parts. In this case, it's generally easier to use a printed book. Help that tries to provide descriptive task-based learning is generally frustrating for a number of reasons-users can't see the help window at the same time they look at the program window, the help window doesn't provide enough space for the long descriptions that are needed, and most users don't want to read a large amount of information from the computer screen anyway.

When creating Help, you should aim to divide it into discrete topics that describe individual windows, complete with all their details. This provides the most useful context-sensitive Help system.

  Tip 

Help can be used for tutorial based learning… but not ordinary help. Instead, applications and games that teach users as they work need to incorporate custom solutions, which are generally referred to as application-embedded support.You look at this technology later in the chapter. Application-embedded support supplements the standardized reference-based Help systems; it doesn't replace them.

 
Chapter 14 - Help and Application-Embedded Support
 
byMatthew MacDonald  
Apress 2002
Companion Web Site
 

Basic Help with the HelpProvider

One easy way to use Help with a .NET application is by adding the HelpProvider control. This "invisible" control shows up in the component tray (Figure 14-5).

Figure 14-5: The HelpProvider

The HelpProvider uses a basic HelpNamespace property that sets the help source. This could be a path to an ordinary .hlp file, an HTML Help .chm file, or even a URL. To bind a control to this HelpProvider, you simply need to set the extended ShowHelp property to true. In other words, when you add a HelpProvider to a form, every control acquires a special property in the designer (with a name like ShowHelp on HelpProvider). Set this to true, and the help file is automatically launched if the user presses the F1 key while this control has focus.

You can also connect or disconnect help manually in code, using the HelpProvider.SetShowHelp() method. Just pass the control that you want to use as an argument.

private void HelpTest_Load(object sender, System.EventArgs e) { // This turns on F1 help support for cmdAdd. hlp.SetShowHelp(cmdAdd, true); // This disables it. hlp.SetShowHelp(cmdAdd, false); }

  Note 

There really isn't any difference between using the SetShowHelp() method and the extended ShowHelp property provided by the designer.With providers, Visual Studio .NET simply translates your selections into the appropriate method calls, and adds the code to the form code. So when you set the ShowHelp property, you are still in fact using the SetShowHelp() method.

You can also set the HelpKeyword and HelpNavigator properties in conjunction to configure which topic is shown when the Help is invoked. Table 14-1 outlines all the possible options you have with the HelpNavigator enumeration. Note that while all these choices are supported by HTML Help, the support in WinHelp and WinHelp 95 is notoriously poor.

Table 14-1: Values for the HelpNavigator Enumeration

HelpNavigator

Description


TableOfContents

Shows the table of contents for the Help file. This is the most common option if you aren't linking to a specific topic.


Index

Shows the index for the Help file, if it exists.


KeywordIndex

Shows the index, and automatically highlights the first topic that matches the HelpKeyword property. For example, if HelpKeyword is "format" for this control, the most similar entry is highlighted in the index list.


Find

Shows the search page for the Help file, which allows the user to perform unguided text searches. This feature tends to provide poorer (and slower) results than the index or table of contents, and is thus avoided if possible.


Topic

The most useful option for context-sensitive help. If you choose this option, you can set the topic identifier as a HelpKeyword. For example, you could use the topic URL in an HTML Help file (like about.htm). When the Help is launched, this topic is browsed to and displayed automatically.


For example, the following two lines of code define a context-sensitive link that binds a control to a specific topic in an HTML Help file.

// Specify a topic link. hlp.SetHelpNavigator(ctrl, HelpNavigator.Topic); // Identify the topic. hlp.SetHelpKeyword(ctrl, "Welcome.html");

Note that the topic name is "Welcome.html." In this case, the example is using a .chm file, and the original HTML Help project included the topic in a source file named Welcome.html. Once the .chm file is created, this file no longer exists separately. Instead, like all topics, it is combined into the compiled help file. However, the file name can still be used as a help keyword to select the topic. Your other option (and your only option with the older WinHelp format) is to use context integers, which are numbers that uniquely identify each topic.

Alternatively, you don't need to use a Help file at all. Instead, you can display a pop-up window with a short message (formerly referred to as "What's This Help"). To do so, make sure that you do not set the HelpProvider.HelpNamespace property, which always takes precedence. Then, either set the HelpString on the HelpProvider property at design-time, or use the SetHelpString method, as shown here:

hlp.SetHelpString(cmdAdd, "Choose another item from the catalog."); hlp.SetHelpString(cmdDelete, "Delete the selected item from your order.");

The resulting pop-up message is shown in Figure 14-6.

Figure 14-6: What's This Help

  Note 

What's This Help was at one point considered a great new approach for creating help, because it doesn't force the user to look in another window. Instead, it integrates help directly in the interface.What's This Help never really caught on, for a number of reasons, including the fact that it only allows the display of limited, unformatted information (for example, you can't bold command names), and it forces the user to understand the rather complicated model of changing focus to the correct control, and then pressing F1.

Note that when you set use the SetHelpString() or SetHelpKeyword() methods, you automatically enable help for the control. That means that you don't need to call the SetShowHelp() method, unless you want to explicitly disable help for the control.

Control Based and Form Based Help

Control-by-control context-sensitivity is usually too much for an application. It's rare that a Help file is created with separate topics for every control in a window, and even if it were, most users simply press F1 as soon as they encounter a confusing setting. In other words, they don't explicitly tab to the setting they want to find out about to give it focus before invoking Help. For that reason, the control that is launching Help is quite possibly not the control the user is seeking information about.

One easy way around this is to define an individual context-sensitive help topic for every form. For a settings dialog, this topic should contain a list of every option. Nicely designed Help might even use dynamic HTML to make this list collapsible (see, for example, Figure 14-7).

Figure 14-7: Collapsible help for one window

The only subtlety to understand with form-based Help is that when you enable Help for the form, you also enable Help for every control it contains. If the user presses F1 while the focus is on a control that is specifically configured with different Help settings, these settings take precedence. If, however, the current control has ShowHelp set to false, the request will be forwarded to the containing form, which launches its own Help. This process works analogously with all container controls, and it allows you to define Help that's as specific as you need, while still being able to fall back on a generic form-wide topic for controls that aren't specifically configured.

  Tip 

The online samples for this chapter include a HelpTest project that shows a simple project with three windows. Each of three windows uses a different granularity of help: form-based, frame-based, and control-based.You can run this application with the included Help file to get a better understanding of the options you have for linking context-sensitive help to an application.

 
Chapter 14 - Help and Application-Embedded Support
 
byMatthew MacDonald  
Apress 2002
Companion Web Site
 

Invoking Help Programmatically

The examples so far require the user to press the F1 key. This automated approach doesn't work as well if you want to provide your own buttons that allow the user to trigger help when needed. Sometimes, this sort of prominent reminder can reassure the user that help is nearby.

To trigger help programmatically, you need to use the static ShowHelp() method of the Help class (found in the System.Windows.Forms namespace). The Help class works analogously to the HelpProvider-in fact, the HelpProvider uses the Help class behind the scenes when the user presses F1.

There are several overloaded versions of the ShowHelp() method. The simplest requires a help filename (or URL) and the control that is the parent for the help dialog (this second parameter is required for low-level Windows operating system reasons). Here's an example that shows the test.hlp file:

Help.ShowHelp(this, "test.hlp");

Additionally, you can use a version of the ShowHelp() method that requires a HelpNavigator, one that requires a keyword, or one that requires both a keyword and a HelpNavigator. Here's an example that could be used for context-sensitive help:

Help.ShowHelp(this, "test.hlp", HelpNavigator.Topic, "about.htm");

To save yourself some work when using this technique with the HelpProvider, you would probably retrieve these values from another control. For example, you might provide a button on your form that invokes the default form help:

private void cmdHelp_Click(object sender, System.EventArgs e) { Help.ShowHelp(this, hlp.HelpNamespace, hlp.GetHelpNavigator(this), hlp.GetHelpKeyword(this)); }

Similarly, you might use a right-click context menu for a control that provides the control's default help:

private void mnuHelp_Click(object sender, System.EventArgs e) { Control ctrl = mnuLabel.SourceControl; Help.ShowHelp(ctrl, hlp.HelpNamespace, hlp.GetHelpNavigator(ctrl), hlp.GetHelpKeyword(ctrl)); }

This menu event handler is written using the SourceControl property, which means it's generic enough to be used with any control. When the menu is clicked, it retrieves the control attached to the menu, and gets its assigned Help keyword.

Help Without the HelpProvider

Now that you are this far, it's possible to unshackle yourself completely from the HelpProvider class. It works like this-handle the KeyDown event of every form that should display help, and check for the F1 key. If it is pressed, launch the appropriate help programmatically with the Help class.

There are two tricks to making this work. The first one is setting the form's KeyPreview property to true, which makes sure it will receive all key press events, regardless of what control has focus. The second sticky point is to make sure you create an event handler for the KeyDown event, not the KeyPress event, which doesn't react to the special F1 key.

The code itself is simple:

private void form1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e) { if (e.KeyCode == Keys.F1) { Help.ShowHelp(this, "test.hlp"); } }

So now that you've seen how it can be done, why would you want to do it? There are actually a number of reasons that you might take this approach when using context-sensitive Help. You examine two of the most common in the next two sections.

Using Database Based Help

Help files, like any other external resource, change. You don't want to embed information like topic URLs all over your user interface, because they are difficult and time-consuming to update. Instead, you can use a basic form event handler that calls a method in a custom AppHelp class. It would look something like this:

private void form1_KeyDown(object sender System.Windows.Forms.KeyEventArgs e) { if (e.KeyCode == Keys.F1) { Global.Help.ShowHelp(this); } }

The Global class simply provides the current AppHelp instance through a static Help member:

public class Global { public static AppHelp Help; }

The AppHelp.ShowHelp() method examines the submitted form, compares it with a list of forms in a database, and thus determines the appropriate context topic, which it launches. Note that for performance reasons, this list of form-topic mappings would be read once when the application starts, and stored in a member variable.

The AppHelp class is shown in the following example. The database code needed to retrieve the FormHelpMappings table has been omitted.

public class AppHelp { public DataTable FormHelpMappings = null; public string HelpFile = ""; public void ShowHelp(Form helpForm) { foreach (DataRow row in FormHelpMappings.Rows) { if (helpForm.Name == Row["FormName"]) { // A match was found. Launch the appropriate help topic. Help.ShowHelp(helpForm, HelpFile, HelpNavigator.Topic, Row["Topic"]); return; } } } }

Using Task Based Help

Another reason you might take control of the help process is to get around the limitations of form-based help. Form-specific help works well in a dialog-based application, but falters when you create a document-based or workspace-based program where users perform a number of different tasks from the same window. Rather than try to write the code needed to dynamically modify help keywords, you can use the AppHelp class to track the current user's task. When Help is invoked, you can use this information to determine what topic should be shown.

Here's the remodeled AppHelp class. Note that in this case, it doesn't decide what topic to show based on form name, but based on one of the preset task types. The logic that links tasks to topics is coded centrally in the AppHelp class (not in the user interface), and it could be moved into a database for even more control. An enumeration is used to ensure that the client code always sets a valid value.

public class AppHelp { // These are the types of tasks that have associated help topics. public enum Task { CreatingReport, CreatingReportWithWizard, ManagingReportFiles, ImportingReport } public string HelpFile = ""; public Task CurrentTask; // Show help based on the current task. public void ShowHelp(Form helpForm) { string topic = "" switch (CurrentTask) { case Task.CreatingReport: topic = "Reports.htm"; break; case Task.CreatingReportWithWizard: topic = "Wizard.htm"; break; case Task.ManagingReportFiles: topic = "Reports.htm"; break; case Task.ImportingReport: topic = "Importing.htm"; break; } Help.ShowHelp(helpForm, HelpFile, HelpNavigator.Topic, topic); } }

Now, the code simply needs to "remember" to set the task at the appropriate times.

Global.Help.CurrentTask = AppHelp.Task.CreatingReport;

When help is invoked, the form doesn't need to determine what task is underway-the AppHelp class simply uses the most recent task setting.

private void form 1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e) { if (e.KeyCode == Keys.F1) { Global.Help.ShowHelp(this); } }

This system could be made much more complex by using a task list or tracking multiple types of context information in the AppHelp class, which is conceptually similar to how many advanced consumer applications (like office productivity software) work.

Creating Your Own Help

Another advanced option you might want to pursue is creating your own Help from scratch, rather than relying on one of the formats I've described. This technique has significant drawbacks: namely, you surrender advanced features like text searching, hierarchical table of contents, and an index. However, it also has significant advantages, the most important being that you can easily integrate Help content into your application. With the current HTML Help system, it is almost impossible to embed and control a help window in your application. MS Help 2 promises some improvements, but the required tools have not yet appeared.

Creating your own Help generally follows two approaches:

  • You store help as long strings in a database record. This generally works best when you are using your custom Help for error messages, a tip of the day feature, or some other simple content.
  • You store links to an HTML file that is contained in the program directory (or a Help subdirectory). This allows you to easily create files using any HTML design tool, take advantage of linking, and even provide the Help externally (possibly through an Internet browser). Hosting an HTML window in your application is much easier than trying to integrate a help window.

These designs allow you to provide a design like the one shown in Figure 14-8. It provides a slide-out window that can be used to give a list of steps with information for the current task. The information itself is retrieved from a database and displayed in the application.

Figure 14-8: Integrated custom Help

You'll notice that this .NET example uses a RichTextBox control to display a formatted list of instructions. RichTextBox controls do not support linking, which makes them less useful for complex Help than a full HTML window. Unfortunately, the .NET Framework does not provide a dedicated HTML control. Instead, you need to import the Internet Explorer ActiveX control, which will efficiently provide the same functionality (see Figure 14-9).

Figure 14-9: Integrated custom HTML Help

This design begins to enter a new topic: application-embedded support, which examines how help can be integrated into applications.

 
Chapter 14 - Help and Application-Embedded Support
 
byMatthew MacDonald  
Apress 2002
Companion Web Site
 

Application Embedded Support

One of the crucial shortcomings with the Help systems you have looked at is that they are all designed to provide fine-grained reference information about specific windows and controls. As I described earlier, help usually fails miserably when it tries to walk the user through a long, involved task. However, better help is possible. What's needed is a change to how help is designed and integrated in applications.

Application-embedded support represents that change. Quite simply, embedded help is user assistance that is a first class member of an application. It's designed as part of the software, not added to the software after it's complete. Embedded help provides far greater user assistance, but also requires far more development work.

Some examples of embedded help include:

  • Process-oriented. Some applications reserve a portion of their interface for continuous tip messages, or use a tiny information icon that a user can click for more information about the current task. This type of help trains users as they work, and is used to great effect in fairly complex computer games (like the popular hit The Sims). Wizards are another example of processoriented help.
  • Stationary embedded. This is the most common form of embedded help, and it refers to the content added to dialog boxes to explain options (affordances) and actual embedded help windows.
  • Agents. This is one of the most advanced and time-consuming types of embedded help. It was pioneered largely by Microsoft in Microsoft Office (and later abandoned). Microsoft's attitude to agents is extremely schizophrenic-it provides tools aimed to make it easy for all developers to use this level of support, but it only occasionally devotes the intense coding time needed to integrate it into its flagship applications.
  • Bidirectional help. To some, this is a holy grail of embedded help, but it's rarely achieved, and usually only in a primitive form. Essentially, one of the critical drawbacks with Help is that it's cut off from the applications in two ways. Not only does the user have to leave the application to read most Help files, but once the appropriate information is found in the Help file, the user has to perform the actual work. There's no way for the Help file to act on the user's behalf, and actually show the user how to do what is needed. Some Help files do provide rudimentary "Show Me" links that can prompt the application to display the appropriate window, but this communication is difficult and fragile. With bidirectional help, Help can perform the necessary task, once it determines what the user needs.

Affordances

Affordances are the visual "clues" designed to demystify a complex application. For example, Windows uses brief descriptions to provide a little information about your computer's Internet settings, as shown in Figure 14-10.

Figure 14-10: A dialog with affordances

Help and affordances represent a bit of a paradox. Nothing can clarify a confusing dialog box more than a couple of well-placed words or icons. On the other hand, users often automatically ignore descriptions, error messages, or anything else that requires reading. They either try to figure out the task on their own or, in the case of an error, repeat the task a few times and then give up.

Given this problem, what is the role of Help in an application? I refuse to believe that Help is useless, as I routinely see innovative games and Web sites that have no problem guiding users through new and unusual interfaces with a few carefully integrated explanations. Unfortunately, the customary current standalone Help is designed to provide reference information. It's very poor at the task-based explanations that most beginning users require-in fact, in this case it's really little more than a limited electronic book.

Integrating Help and user interface

Of course, integrating help content into the user interface is not a happy solution for the programmer. To fend off the cycle of endless recompiles and tweaking, you can try to read information dynamically from a database, but this approach usually fails because the content is not guaranteed to be the appropriate length and fit in an attractive way in the space provided. Windows controls and Forms have fixed bounds, and do not automatically resize to fit their contents unless you add the code to accommodate this behavior.

Generally, the most practical approach is to add a few words when needed in a dialog box, but to fall back on a secondary window embedded in the application for more extensive information. This window, which you explored in the previous section, is the perfect compromise-it doesn't force the user to leave the application, and it can easily accommodate HTML or RTF documents of various lengths and with embedded formatting. Microsoft is also beginning to standardize a variation of this approach in some of its latest releases.

Agents

Agents are the animated characters that appear in applications to guide users through a task. The most infamous example of Agents is the (now defunct) Clippy character included with Microsoft Office. Most developers don't consider agents for their applications because of several factors:

  • Agents require first-rate design work. An ugly agent is worse than no agent at all.
  • Agents require tedious programming. Every action or tip the agent gives must be individually triggered by the application code. If not handled properly, this can lead to Help code that is tangled up with the application's core functionality.
  • Agents are "silly," and appeal more for their novelty than for any actual assistance they provide.

These are legitimate concerns. However, in a consumer application, an agent can also act as an appealing and distinctive feature that attracts the user's attention. Agents also perform the remarkable trick of turning tedium into fun. Quite simply, users often enjoy using programs with agents.

Creating a program with agent support is not as difficult as most developers believe, because Microsoft provides some remarkable tools, and a set of four standard characters that can be freely distributed with your applications. To download the agent libraries, refer to http://msdn.microsoft.com/library/en-us/msagent/userinterface/3y2a.asp. The Microsoft Agent Control is only available as a COM component, but it can be easily consumed in a .NET program by creating a runtime callable wrapper, a task Visual Studio .NET carries out automatically when you add the reference. Figure 14-11 shows the reference you must add for the Microsoft Agent control.

Figure 14-11: The Microsoft Agent control

The Microsoft Agent Control allows you to use Merlin, a Genie, Peedy (a bird), or Robbie (a robot), or all of them at once. All components are complete with rotoscoped animations, can perform various actions as you direct them, can move about the screen, can think or "speak" text (either using a poor voice synthesizer that's included, or a wave file you specify). When speaking with a voice file, the characters' mouths even move to synchronize closely with the words, creating a lifelike illusion. Best of all, Microsoft quietly gives these features away for free. You can purchase other Agent characters from third-party sites online, or create them independently, although the tools provided won't help you create lifelike animations on your own.

The online samples include an AgentTryout application that allows you to put an agent character through its paces, speaking and thinking the text you specify, moving about the screen, and performing various animations (see Figure 14-12).

Figure 14-12: The agent tryout application

The AgentTryout application interacts with any of the four agent characters through a special AgentController class, which encapsulates all the functionality for controlling movements, speech, and action. This class code can be reused in any application.

public class AgentController { // Agent variable. private AgentObjects.IAgentCtlCharacterEx agentChar; // Name of the initialized character. private string characterName; // Balloon constants private const short BalloonOn = 1; private const short SizeToText = 2; private const short AutoHide = 4; private const short AutoPace = 8; public AgentController(AxAgentObjects.AxAgent agentHost, string character) { agentHost.Characters.Load(character, null); agentChar = agentHost.Characters[character]; characterName = character; // You could put your own options in this menu, if desired. agentChar.AutoPopupMenu = false; // Set balloon style. agentChar.Balloon.Style = agentChar.Balloon.Style | BalloonOn; agentChar.Balloon.Style = agentChar.Balloon.Style | SizeToText; agentChar.Balloon.Style = agentChar.Balloon.Style | AutoHide; agentChar.Balloon.Style = agentChar.Balloon.Style & (!AutoPace); } public void Dispose() { if (agentChar.Visible) { agentChar.StopAll(null); agentChar.Hide(null); } } public void Show() { agentChar.Show(null); } public void Hide() { agentChar.Hide(null); } public void StopAll() { agentChar.StopAll(null); } public void Speak(string text) { agentChar.StopAll(null); agentChar.Speak(text, ""); } public void Think(string text) { agentChar.StopAll(null); agentChar.Think(text); } public void Animate(string animation) { agentChar.StopAll(null); agentChar.Play(animation); } public void MoveTo(short x, short y) { agentChar.MoveTo(x, y, null); } public void GestureAt(short x, short y) { agentChar.GestureAt(x, y); } public Array GetAnimations() { ArrayList list = new ArrayList(); foreach (string animation in agentChar.AnimationNames) { list.Add(animation); } return list.ToArray(typeof(string)); } // Tests if the agent is visible. // If the agent is not visible it will be shown. private bool IsAgentVisible() { if (agentChar.Visible) { return true; } else { agentChar.Show(null); return false; } } }

Using the AgentController class is easy. All you need to do is create an instance of the Microsoft Agent Control on your form, and then create a new instance of the AgentController class using the interop class. The AgentController wraps all the functionality you will need to use. All you need to do is call the appropriate method.

For example, the AgentTryout project uses the code below to create the Agent and fill a list control with a list of supported animations:

private AgentController controller; private void Form1_Load(object sender, System.EventArgs e) { // Create the agent. controller = new AgentController(axAgent1, "Genie"); // List the supported animations. lstAnimations.DataSource=controller.GetAnimations(); // Show the agent. controller.Show(); }

The animation is played with a single line of code in response to a button click:

private void cmdPlay_Click(object sender, System.EventArgs e) { controller.Animate(lstAnimations.Text); }

Moving, thinking, and speaking (shown in the following) are similarly easy:

private void cmdSpeak_Click(object sender, System.EventArgs e) { controller.Speak(txtSpeak.Text); }

Even if you don't like the idea of animated characters, it's hard to complain about the agent control. Similar functionality from a third-party developer comes at quite a price.

  Note 

To use the Agent control successfully, you need to use Microsoft's ActiveX control version, which is normally used only in Web pages. The COM component version, which is described in the documentation for use with Visual Basic 6, will not work correctly in a .NET program. Luckily, both the ActiveX control and the COM component provide the same interface to interact with the agent character.

 
Chapter 14 - Help and Application-Embedded Support
 
byMatthew MacDonald  
Apress 2002
Companion Web Site
 

The Last Word

This chapter began with the built-in .NET Framework support for Help, and then began to expand on it with integrated help and animated agents. In the process, the chapter delved into the old world of ActiveX components, demonstrating that COM is far from gone, even after the .NET revolution.

Help strategies and systems vary widely depending on the intended audience and the application design. In this chapter we toured the wide and diverse world of Help programming. None of the solutions examined here can be used in every scenario. Instead, it helps to keep some basic principles in mind:

  • A help file should describe the purpose of various settings, not how to use common controls. No one needs an explanation about how to click a check box. Instead, users need to know why they should click the check box.
  • The best affordances are descriptive labels, not instructions. No dialog box has the space or formatting power of a printed document.
  • The best error is one that doesn't happen. It may take more effort in your code to disable or hide invalid options, but it prevents dozens of common mistakes in the input fields.
  • Help must be context-sensitive. A confused user won't search through a Help file to find a relevant topic—a printed document is better at that.
  • Perform usability tests. When writing a program, you design based on who you believe the audience is. At some point, you need to bring in some new users, and find out what their capabilities really are.
 
Index
 
byMatthew MacDonald  
Apress 2002
Companion Web Site
 

Index

Категории