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.