Introduction
The .NET framework offers us the Help
class and the HelpProvider
component to seamlessly integrate a Help system into our applications. Surprisingly, integrating the regular done-to-death Help techniques into your application with the use of the HelpProvider
component in .NET is insufficiently illustrated in the VS.NET documentation. However, learning on your own, turns out to be anything but difficult.
"The Windows Forms HelpProvider
component is used to associate an HTML Help 1.x Help file (either a .chm file, produced with the HTML Help Workshop, or a .htm file) with your Windows application. The HelpProvider
component can be used to provide context-sensitive Help for controls on Windows Forms or specific controls. Additionally, the HelpProvider
component can open a Help file to specific areas, such as the main page of a table of contents, an index, or a search function."-MSDN
With VB6, I should admit that Help was perhaps the last feature I was inclined to incorporate into an application. Even providing pop up context-sensitive help windows required garnering Win32 API support (getting enough info was tough by itself). With .NET, this tendency of mine (and that of anybody else who can be just as lazy) has begun to disappear. It is so easy to provide the pop-up window support now, that I use them right from the start of UI construction.
.NET immediately allows your help system to be based on a pop-up-window or/and online/offline HTML approach. The .CHM file approach is my favorite, simply for the Keyword Indexing feature, if not for anything else. Let's face it. No approach is without pitfalls. An online help would make maintainability sleek and accurate, but not many applications warrant the need for a user to connect to the Internet to get some assistance. This article will demonstrate how to include each approach using the leverage .NET offers. Note that the ToolTip and background information on how to create Help files using HTML Help Workshop will not be discussed.
Background
HelpProvider Class
"Provides pop-up or online Help for controls. ��Each instance of HelpProvider
maintains a collection of references to controls associated with it."-MSDN
The HelpProvider
component implements the very special IExtenderProvider
interface, whereby it becomes capable of providing extra properties to other components. MSDN gives a decent description about the interface, so I suggest that the insatiable reader look it up.
The HelpProvider
component can be dragged on to your Windows Form from the Toolbox. It will likely be automatically named HelpProvider1
. I normally change it to something like hlpPrvMain
or anything more appropriate and on the mark. The only really relevant property you need to set at design-time is the HelpNamespace
property, which holds a string value representing the path to the HTMLl Help source file. The source file may be any .htm or .chm file. However, I later found that it could be used to point to even a .txt file or any file for that matter, only that it serves very little purpose. Alas!
Extender Properties
The HelpProvider
component associates itself very neatly with your form and all the controls on it without ado. You can make sure of this fact by checking for HelpXXX
properties that come out of nowhere for every control in the Properties window. I have read somewhere that the component maintains a separate hashtable for each property it provides to all external objects. The properties added include the following: -
HelpButton
This property takes a boolean value and determines whether the Help symbol (?) appears on your form in the control box. The button will however appear only if the MaximizeBox
and MinimizeBox
properties for the form are also set to false. Hence, the Help button is a feature normally seen only on Dialog forms.
HelpNavigator
Specifies a constant indicating which elements of the Help file to display. It can be any one of the values in the Enum
HelpNavigator
(as listed in MSDN): -
TABLE 1.
Member name |
Description |
AssociateIndex |
Specifies that the index for a specified topic is performed in the specified URL. |
Find |
Specifies that the search page of a specified URL is displayed. |
Index |
Specifies that the index of a specified URL is displayed. |
KeywordIndex |
Specifies a keyword to search for and the action to take in the specified URL.
|
TableOfContents |
Specifies that the table of contents of the specified URL is displayed. |
Topic |
Specifies that the topic referenced by the specified URL is displayed. |
HelpKeyword
The Help
keyword provides the key information to retrieve the help associated with this control from the Help file specified by HelpNamespace
. It takes a string value that means different things for different values of the HelpNavigator
property. Refer to table 2 below.
TABLE 2.
HelpNavigator Value |
What the HelpKeyword value represents. |
AssociateIndex |
Applies exclusively to .chm files. The string value is treated as a match criterion to find the most minimal match in the Help Index that would be just enough to get a unique hit. But the topic is not displayed. |
Find |
Applies exclusively to .chm files. The string value is seemingly ignored resulting in the Find section of the Help file being displayed. |
Index |
Applies exclusively to .chm files. The string value is entered into the Index Find textbox, but the related topic is not displayed. |
KeywordIndex |
Applies exclusively to .chm files. The string value is not only entered into the Index Find textbox, but the related topic is displayed as well. |
TableOfContents |
Applies exclusively to .chm files. The string value is seemingly ignored resulting the Contents section of the Help file being displayed. |
Topic |
The string value is taken as the name of a file. The value can optionally include an anchor. E.g., �index.htm#top�. |
HelpString
The HelpString
value represents the help message of the pop-up help windows that appear when the user requests for Help using the Help button or by pressing F1.
Important Public Members
At design-time, you can associate an instance of HelpProvider
with only one Help source. Your Help source can be set through the HelpNamespace
property which accepts a string value representing the path to your .htm or .chm file. This property is the only useful property exposed in the component. It is used to contain the name of the help file, which may be an .htm or .chm file (there is nothing stopping you from providing a path to a text file or even a .exe file, but doing so is not really useful). Additionally, it exposes quite a few useful methods: -
SetHelpKeyword
Specifies the keyword used to retrieve Help when the user invokes Help for the specified control.
Overridable Public Sub SetHelpKeyword (ByVal ctl As Control, _
ByVal keyword As String)
This string value is used to find the specific help section in the help file that pertains to the specified control.
SetHelpNavigator
Specifies the Help command to use when retrieving Help from the Help file for the specified control.
Overridable Public Sub SetHelpNavigator (ByVal ctl As Control, _
ByVal navigator As HelpNavigator)
This method determines which element of the Help File to Display.
SetHelpString
Specifies the Help string associated with the specified control.
Overridable Public Sub SetHelpString (ByVal ctl As Control, _
ByVal helpString As String)
This method sets the Help string, but does not display the pop-up message. The pop-up will appear the next time the user presses F1 on the control.
SetShowHelp
Specifies whether Help is displayed for the specified control.
Overridable Public Sub SetShowHelp (ByVal ctl As Control, _
ByVal value As Boolean)
This method is used to override the flag that determines whether the Help for a control will be displayed or not.
The above-mentioned SetXXX
methods have related GetXXX
methods as well, as listed below:-
GetHelpKeyword
GetHelpNavigator
GetHelpString
GetShowHelp
The HelpProvider
also registers event handlers on each control's HelpRequested
and QueryAccessibilityHelp
events.
Help Class
"Encapsulates the HTML Help 1.0 engine. ��You can use the Help
object to show compiled Help files (.chm) or HTML files in the HTML Help format. Compiled Help files provide table of contents, index, search, and keyword links in pages. Shortcuts work only in compiled Help files. You can generate HTML Help 1.x files with the HTML Help Workshop."-MSDN
This is another class that has very little documentation. Look it up on MSDN, here's what you will be told - "This member supports the .NET Framework infrastructure and is not intended to be used directly from your code". Regardless, note that it is found in the System.Windows.Forms
namespace, and used to explicitly display Help files from your code. It exposes two useful shared/static methods for our consumption:-
ShowHelp
Displays the contents of a help file.
To display the contents of the Help file at the specified URL:
Overloads Public Shared Sub ShowHelp(ByVal parent As Control, _
ByVal url As String)
To display the contents of the Help file found at the specified URL for a specific topic:
Overloads Public Shared Sub ShowHelp(ByVal parent As Control, _
ByVal url As String, ByVal navigator As HelpNavigator)
To display the contents of the Help file found at the specified URL for a specific keyword:
Overloads Public Shared Sub ShowHelp(ByVal parent As Control, _
ByVal url As String,ByVal keyword As String)
To display the contents of the Help file located at the URL supplied by the user:
Overloads Public Shared Sub ShowHelp(ByVal parent As Control, _
ByVal url As String, ByVal navigator As HelpNavigator, _
ByVal param As Object)
I learnt a very interesting thing about this method. It will open just about any URL you provide to it. The URL can point to any local or remote resource. It was a pleasant surprise to know that it could even run an EXE file. Very interesting indeed! In overloaded versions that require extra parameters, pass in Nothing
and you will infer that those parameter values are ignored, or at least they don't interfere with running the file.
ShowHelpIndex
Displays the index or search window of a help file.
Public Shared Sub ShowHelpIndex(ByVal parent As Control, _
ByVal url As String)
ShowPopUp
Displays pop-up help at chosen location on screen.
Public Shared Sub ShowPopup( ByVal parent As Control, _
ByVal caption As String, ByVal location As Point)
Using a HelpProvider object to add Pop-up Help
Pop-up help involves providing context-sensitive information for a control or a form. The help message or information is embedded in your code. The context-specific pop-up help message will be displayed when a user presses F1 on the control that has the focus.
Once the HelpProvider
component has been added to the Form
, we can set the HelpString
for every control on the form we intend to provide Help. Depending upon the number of HelpProvider
components you have made use of, you will find an equal number of HelpString
properties for very control, pertaining to each HelpProvider
instance. Set the value of the HelpString
property (of the HelpProvider
you want to use to provide pop-up help) to a useful message for each control. Make sure the ShowHelp
property (pertaining to the same HelpProvider
instance) is set to true for the concerned controls. It would be advisable to use a single HelpProvider
to provide pop-up help on the same form just to make maintenance a lot easier. Once these two properties are set at design time, our work is done! None of the other newly available properties need to be configured.
The same design-time configuration can be done by code as well. However, the properties that we set at design-time for each control using the Properties window are not available at runtime. Instead, we make use of the SetHelpString
method of the HelpProvider
component, or the Shared
Help.ShowPopUp
method as illustrated below.
Help.ShowPopup(Me, _
"Enter Phone number here. Valid input characters are 0-9,space,'-','(', and ')'", _
Cursor.Position)
OR
hlpPopUp.SetHelpString(txtCity, _
"You pressed F1 on the City field. How can I help you?")
hlpPopUp.SetShowHelp(txtCity, True)
See the Pop-up Demo in the code that comes with this article.
Enabling The Help Button
The Help button (appears with '?' as its text.) occurs on the RHS of your title bar as shown in the picture below (the images come from some quick demo apps I put together for the article).
You can enable this button for your form by setting its boolean HelpButton
property to True
. The catch in using this button in your forms is that you have to do away with the Maximize
and Minimize
boxes in the title bar. So, go ahead and set the MaximizeBox
and MinimizeBox
properties to False
.
Clicking the Help button at runtime will change your cursor to show "?". With the new cursor displayed, click on the field for which you may have set the HelpString
property and the pop-up Help should now get displayed.
See the Pop-up Demo in the code that comes with this article.
HelpRequested Event
Every control, including the form, raises its own HelpRequested
event in response to a user pressing the F1 button. We are rightly advised to do our Help invocation implementation here if we want to exercise greater control over the process.
Example:
Private Sub txtPhone_HelpRequested(ByVal sender As Object, _
ByVal hlpevent As System.Windows.Forms.HelpEventArgs) _
Handles txtPhone.HelpRequested
Help.ShowPopup(Me, _
"Enter Phone number here. Valid input characters are 0-9", _
hlpevent.MousePos)
End Sub
However, it is possible to respond to a user's help request from the KeyDown
or one of the other key-related events as well, simply by screening for the KeyCode
value and performing the necessary action if it evaluates to the F1 button. Note that the HelpRequested
event will fire regardless after key-based events.
'E.g.,
Private Sub txtPhone_KeyDown(ByVal sender As Object, _
ByVal e As System.Windows.Forms.KeyEventArgs) Handles txtPhone.KeyDown
If e.KeyCode = Keys.F1 Then
Help.ShowPopup(Me, _
"Enter Phone number here. Valid input characters are 0-9",Cursor.Position)
e.Handled = True
End If
End Sub
Adding Offline/Online .Htm Help
Using HelpProvider Class
The first step would be to set the HelpNamespace
property to a valid URL. The URL will be a local path for an offline web page or a remote URL (e.g., "http://www.codeproject.com") for an online web page. At design-time, you can hard code the path to your help resource in the HelpNamespace
property of the HelpProvider
component.
This much will suffice to get the page to display in your default browser when the user presses F1. You don't really have to change any other properties.
To use the same HelpProvider
component to display different web pages for different contexts, you have to programmatically change the HelpNamespace
property value to the appropriate Help resource. You can do the change in the HelpRequested
event.
Private Sub lnkOpenHtmHelpIndex_HelpRequested(ByVal sender As Object, _
ByVal hlpevent As System.Windows.Forms.HelpEventArgs) _
Handles lnkOpenHtmHelpIndex.HelpRequested
hlpPopUpAndHtm.HelpNamespace = IO.Path.GetDirectoryName(.HelpNamespace) & _
"\help_on_city.htm"
End Sub
It is also easy to open your help web page in response to other user events, like say a click event. Take a look below:
Private Sub lnkOpenHtmHelpIndex_LinkClicked(ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs) _
Handles lnkOpenHtmHelpIndex.LinkClicked
hlpPopUpAndHtm.HelpNamespace = IO.Path.GetDirectoryName(.HelpNamespace) & _
"\help_on_city.htm"
SendKeys.Send("{F1}")
End Sub
See the Help File Demo in the code that comes with this article.
Using Help Class
Just in case, you wish to use the System.Windows.Forms.Help
class for the same, then we have to do something like this:-
E.g.,
Help.ShowHelp(Me, "http://www.codeproject.com")
Or
Help.ShowHelp(Me, "\Help\index.htm")
See the Help File Demo in the code that comes with this article.
Adding Offline/Online .chm Help
Using HelpProvider Class
Associating the HelpProvider
component with a .chm file is the most preferred way of going about designing and integrating a help system for a WinForms application from what I hear, and not without obvious reasons. Compiled help files provide table of contents, index, search, and keyword links in pages.
So first things first! Set the HelpNamespace
property of the component to a valid URL that points to your .chm help file. The .chm file is normally located at an address local to the client, but there may be needs for the file to be located on a remote location on a LAN or the Internet. Regardless, the property value should pay heed to your need.
With that done, set the "ShowHelp On HelpProvider" for the control (for which you want to associate with the Help file's contents) to true. Choose an appropriate HelpNavigator
Enum
value so that the desired section of the help file will be opened and queried using your HelpKeyword
value. The latter should hold a context-specific keyword that you had included in the Help file before compilation. It could be an index entry, a search value or the name of a file that is part of the compilation. In each case, the value of the HelpNavigator
has to be set to specific values as explained in table 2 presented earlier in this article.
That's all there is to be done at design time.
If you want to change the HelpKeyword
and/or the HelpNavigator
properties of a control at runtime, use the SetHelpKeyword
and/or the SetHelpNavigator
methods of the HelpProvider
component.
See the Help File Demo in the code that comes with this article.
Using Help Class
The Help
class can be used during runtime to display the contents of your .chm file as well.
To show the table of contents, do something like this:
Help.ShowHelp(Me, "Help\VB.chm", HelpNavigator.TableOfContents)
Change the HelpNavigator
Enum
value to show other sections of the help file.
If you want to show the Index section, either one of the two statements should do the job:
Help.ShowHelpIndex(Me, "Help\VB.chm")
OR
Help.ShowHelp(Me, "Help\VB.chm", HelpNavigator.KeywordIndex)
To display a particular file in the compiled help source, try the following:
Help.ShowHelp(Me, "Help\VB.chm", "help_on_name.htm")
See the Help File Demo in the code that comes with this article.
Associating Alternate Keys To Invoke Help
It is not entirely necessary to associate Help with the F1 key alone. It's real easy to launch help using any other key or combination, but you have to provide code for that end.
E.g.,
Private Sub txtName_KeyDown(ByVal sender As Object, _
ByVal e As System.Windows.Forms.KeyEventArgs) _
Handles txtName.KeyDown
If e.KeyCode = Keys.F1 And e.Alt Then
Help.ShowPopup(txtName, "This is an alternative help message", _
New Point(Me.Location.X + txtName.Location.X, _
Me.Location.Y + txtName.Location.Y))
End If
End Sub
Points of Interest
It would be interesting to know that when you invoke a web page (whether local or remote) using the Help.ShowHelp
method, you are opening your browser window in an external process. This means that when your client application process dies, the browser process holds its ground unless you had earlier closed it yourself. It can be embarrassing if your Help file hangs around after the application that called it has shut down. However, it does not happen with .chm files that are opened with the HelpProvider
component.
As a work around, I suppose we could use an instance of the Process
class found in the System.Diagnostics
namespace. Here's a quick snap class I devised solely for demonstrating my idea. It could and should rightly be bettered before it's actually used.
Namespace KingLeon
Public Class Help
Public Shared Function ShowHelp(ByVal url As String) _
As System.Diagnostics.Process
Dim startInfo As New Diagnostics.ProcessStartInfo()
With startInfo
. FileName = url
.WindowStyle = ProcessWindowStyle.Normal
End With
Return System.Diagnostics.Process.Start(startInfo)
End Function
Public Shared Sub CloseHelp(ByVal proc As System.Diagnostics.Process)
If Not proc Is Nothing Then
If Not proc.HasExited Then proc.Kill()
End If
End Sub
End Class
End Namespace
The method KingLeon.Help.ShowHelp
is a function that returns a Process
object. This Process
object can be stored in a collection in the calling application for later reference in case the application decides to shut down. In which case, we will have to iterate through each Process
object in the collection and call the KingLeon.Help.CloseHelp
method, which takes a Process
object as a parameter. The collection I used was the ArrayList
, which I simply rate as one of the best things .NET provides.
Private procList As New ArrayList()
........
........
........
Private Sub mnuItmOnlineHelp_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles mnuItmOnlineHelp.Click
procList.Add(KingLeon.Help.ShowHelp("http://www.codeproject.com"))
End Sub
........
........
........
Private Sub frmHelpFile_Closing(ByVal sender As Object, _
ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
If Not procList Is Nothing Then
Dim i As Integer
For i = 0 To procList.Count - 1
KingLeon.Help.CloseHelp(CType(procList(i), Diagnostics.Process))
Next
End If
End Sub
See the Help File Demo in the code that comes with this article.
Using the code
The code with this article gives simple demonstrations on how what we have discussed in this article can possibly be used. The two main classes of interest are frmHelpFile.vb and frmPopUp.vb. The former illustrates how to interact with a file-based Help System, while the latter shows how pop-up based Help can prove useful. Fair enough?