When you think ASP, think...
Recent Articles xml
All Articles
ASP.NET Articles
Related Web Technologies
User Tips!
Coding Tips
spgif spgif

Book Reviews
Sample Chapters
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Stump the SQL Guru!
Web Hosts
Author an Article
spgif spgif

ASP ASP.NET ASP FAQs Feedback topnav-right
Print this Page!
Published: Wednesday, August 23, 2006

Programmatically Creating Context-Sensitive Help on a Web Page

By Scott Mitchell


In last week's article, Creating Context-Sensitive Help on a Web Page, we looked at how to associate rich help "tooltips" with certain regions in the browser. With a bit of client-side JavaScript and HTML markup, this previous article illustrated how to have a help window with images and rich text appear when mousing over an image or specific text. Such context-sensitive help is a great way to include extra information or a more detailed explanation of data on a web page in a space-saving manner.

Last week's article aimed to simply lay the ground work for creating a context-sensitive help system and, as such, had a few shortcomings. Most noticeably, the help window appeared immediately when mousing over its associated region and disappeared immediately after mousing out of that region. This behavior introduced two usability issues: first, when moving the mouse over the screen, if you happened to pass over a help region the help window appeared, which could be jarring; second, if a help window contained links or was lengthy enough to require scrolling, when attempting to move the mouse from the help region to the help window, the mouse would leave the help region and the help window would disappear.

In addition to these two end user usability problems, the context-sensitive help system presented last week wasn't very user friendly for us, the page developer. All of the script and <div> and <iframe> elements needed to be manually added to the web page to define the help windows and the onmouseover and onmouseout event handlers for the help region. Ideally, all of the necessary script and markup could be added programmatically, with a single line of code from the ASP.NET code-behind class.

In this article we'll see how to improve upon the rudimentary context-sensitive help system from last week by fixing the aforementioned usability concerns and by creating an ASP.NET 2.0 class with methods to programmatically add the help windows and needed script for a given help region. Read on to learn more!

If you've not yet read Creating Context-Sensitive Help on a Web Page, please do so before continuing with this article...

- continued -

Delaying Before Opening and Closing Help Windows

When mousing over a tooltip-enabled user interface element in a web page or Windows application, the tooltip doesn't immediately appear, but only after hovering over its help region for a short time. The context-sensitive help system explored in last week's article, however, immediately shows the help window when a help region is moused over. This immediacy can have a jarring effect for the user if they move their mouse across their browser screen. Even though they didn't intend for any context-sensitive help to popup, their mouse's flight across the screen may have inadvertently passed through one or more help regions, thereby causing the help window to display. Granted, these help windows quickly disappeared as the user continued to move their mouse across the screen, but the quick flash of the help window might confuse or annoy users.

To remedy this, we can introduce a slight delay before displaying a window. That is, when the user mouses over a help region, rather than display the help window immediately, we wait for half a second (or what have you) and then show the help window. If, in that half second waiting period, the user's mouse has left the help region, then we'd not show the help window.

JavaScript provides the setTimeout(expression, delay) function to perform a given expression after a specified number of milliseconds delay. When using setTimeout it's vital to understand that the function is non-blocking. That is, when the setTimeout statement is reached, it adds the expression to a queue to be executed after the specified delay. The lines of JavaScript immediately after the setTimeout function are then executed without pause. In other words, the delay specified before executing the specified expression is asynchronous. The control flow does not wait at the setTimeout command until the specified delay has passed.

To accomplish this, I broke out the csi_showHelpFloatWindow - which displays a specified help window - into two functions:

  • csi_showHelpFloatWindow - accepts the same set of input parameters as before along with a new one, waitDurationInMilliseconds. The waitDurationInMilliseconds parameter indicates how many milliseconds to pause between mousing over a help region and displaying its help window. This function calls the csi_showHelpFloatWindowInternal using the setTimeout function.
  • csi_showHelpFloatWindowInternal - does the actual work of displaying the help window.
Additionally, we need a flag variable that indicates whether or not to cancel the opening of the window. For example, if a user mouses over a help region, the csi_showHelpFloatWindow is called and the setTimeout function instructs that the csi_showHelpFloatWindowInternal function is to be called after, say, 500 milliseconds (half a second). If the user moves their mouse out of the help region before the 500 millisecond delay has expired, we do not want to display the help window. However, the csi_showHelpFloatWindowInternal function will still execute, there's no way to cancel it based on the mouse movements.

Therefore, we use a flag variable that indicates whether or not the open command has been cancelled - it's set to false in csi_showHelpFloatWindow and to true in the onmouseout event handler of the help region. When the csi_showHelpFloatWindowInternal function executes, it only proceeds if the cancel flag is false. Since there may be different help window types on a page (that is, help windows with different windowIDs), a single flag variable won't do. Rather, we need a flag for each unique help window type. This is accomplished through an array, as the following JavaScript highlights:

// Array to hold the 'flags' to determine whether a window's open has been cancelled

var csi_cancelOpenArray = new Array();

function csi_showHelpFloatWindow(windowID, objID, horizPadding, vertPadding, goRight, waitDurationInMilliseconds)
   // keep the window open
   csi_cancelOpenArray[windowID] = false;

   setTimeout("csi_showHelpFloatWindowInternal('" + windowID + "','" + objID + "'," + horizPadding + "," + vertPadding + "," + goRight + ");", waitDurationInMilliseconds);


function csi_showHelpFloatWindowInternal(windowID, objID, horizPadding, vertPadding, goRight)
   // exit function immediately if open command has been cancelled

if (csi_cancelOpenArray[windowID] == true) return;

   ... Same logic for displaying the help window as seen in last week's article ...

When the user mouses out of a help region, we need to set the flag (csi_cancelOpenArray[windowID]) to true. This is accomplished by updating the csi_hideHelpFloatWindow function (which, recall, is executed from the help region's onmouseout event).

function csi_hideHelpFloatWindow(windowID)
   // cancel the open
   csi_cancelOpenArray[windowID] = true;


This same pattern is repeated to add a delay when between when mousing out of a help region whose help window is open, and closing that help window. This delay allows the user to move their mouse from the help region to the help window, where they can interact with the help window (scroll through its contents, click a hyperlink, and so on). To facilitate this, another flag array is used (csi_cancelCloseArray), which is set to false when leaving a help region (in the csi_hideHelpFloatWindow function) and set to true when mousing over a help region or when mousing over the help window itself. As with the delay before opening, this is accomplished by splitting the csi_hideHelpFloatWindow function into two functions:

  • csi_hideHelpFloatWindow - accepts an additional input parameter waitDurationInMilliseconds, which indicates how many milliseconds to pause between mousing out of a help region and hiding its help window. This function calls the csi_hideHelpFloatWindowInternal using the setTimeout function.
  • csi_hideHelpFloatWindowInternal - does the actual work of hiding the help window.

// Array to hold the 'flags' to determine whether a window's close has been cancelled

var csi_cancelCloseArray = new Array();

function csi_hideHelpFloatWindow(windowID, waitDurationInMilliseconds)
   // cancel the open
   csi_cancelOpenArray[windowID] = true;

   // wait before hiding window
   csi_cancelCloseArray[windowID] = false;

   setTimeout("csi_hideHelpFloatWindowInternal('" + windowID + "');", waitDurationInMilliseconds);


function csi_hideHelpFloatWindowInternal(windowID)
   // exit function immediately if close command has been cancelled

if (csi_cancelCloseArray[windowID] == true) return;

   ... Same logic for hiding the help window as seen in last week's article ...
[View a live demo!]

Additionally, the csi_showHelpFloatWindow and the onmouseover event of the help window set the appropriate flag in csi_cancelCloseArray to true. Refer to the complete JavaScript and code library available for download at the end of this article for more information.

Adding Context-Sensitive Help Programmatically

There are a number of client-side tasks we need to complete in order to associate a help window with a particular region, including:
  • The JavaScript needed to show and hide the help windows
  • The CSS styling for the help window (its z-index, configuring it for absolute positioning, and so on)
  • The help window markup (the <div> and <iframe> tags)
Manually adding these various pieces to each page that needs context-sensitive help is tedious and error-prone. Instead, it would be ideal to be able to associate a help window with a region on the screen through a single line of code from the ASP.NET page's code-behind class. This lone method call would automatically inject the necessary JavaScript, CSS, and help window markup.

To implement this, I created a class named ContextSensitiveHelp that contains the context-sensitive help-related methods. ContextSensitiveHelp derives from the System.Web.UI.Page class. To utilize its context-sensitive help-related methods in an ASP.NET page, adjust your ASP.NET page's code-behind class so that it derives from ContextSensitiveHelp rather than from System.Web.UI.Page. See Using a Custom Base Class for your ASP.NET Page's Code-Behind Classes for more information on this technique and its advantages.

The ContextSensitiveHelp class contains a single page-level accessible method, AddContextSensitiveHelp, which has a variety of overloads. At minimum, you must pass this method:

  • The Web control that serves as the help region (perhaps a Label Web control or an Image Web control),
  • The windowID (an arbitrary string that is used to identify a help window for opening and closing the window), and
  • The URL of the help web page to display in the help window
You can optionally include input parameters like whether the help window opens to the right or left of the help region, the width and height of the window, the amount of horizontal and vertical padding between the help region and the help window, and the delay time (in milliseconds) for opening and closing the help windows. Whenever the AddContextSensitiveHelp method is called, the needed JavaScript and CSS is added (if needed) and the help window markup is added.

For example, to associate a help window with a Label control named WelcomeLabel, you could add the following line of code to the Page_Load event handler:

AddContextSensitiveHelp(WelcomeLabel, "GeneralHelp", "~/HelpFiles/GeneralHelp.aspx")

To try out the ContextSensitiveHelp class, download the project files available at the end of this article.

ContextSensitiveHelp and ASP.NET Version 1.x
The ContextSensitiveHelp class was created in Visual Studio 2005 and is intended to be used in an ASP.NET 2.0 web application. It uses classes and methods new to the .NET Framework 2.0 with regards to emitting the client-side script, and therefore won't work, as-is, in an ASP.NET 1.x application. However, the script features new to 2.0 can be accomplished in 1.x with minor modifications. For more on programmatically working with client-side script in an ASP.NET 1.x application, check out: Working with Client-Side Script.

Conclusion & Looking Forward...

We've made some great improvements to the context-sensitive help system first introduced in last week's article, Creating Context-Sensitive Help on a Web Page. We saw how to use the JavaScript setTimeout function to add a brief delay before showing a help window and how to leave the help window displayed after mousing out of the help region. Furthermore, we examined the ContextSensitiveHelp class, which provides a simple method for creating and associating a help window with a help region.

There are still a few shortcomings of the context-sensitive help system, though. For one, the help windows require an explicitly specified height and width, and do not adapt to their actual content. For example, consider a help window sized at 400x350, but whose help content contains just a few words. Ideally this help window would be smart enough to resize itself to, say, 200x150, to reduce the whitespace in the window. Additionally, if the help region is near the border of the browser (at the right or bottom), the help window will likely be cut off by the bottom or right of the browser. Ideally, the help system would be intelligent enough to position itself to the left if it was going to be cut off on the right or to raise its top position if it was going to be cut off at the bottom. Perhaps a future article will tackle these issues!

Happy Programming!

  • By Scott Mitchell


  • Download the complete code samples examined in this article (in ZIP format)

  • ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article