Help


As useful as the ErrorProvider user interface is (at least compared with the status bar), it would be nice to provide help to our users that didn't take the form of a reprimand. It would also be useful to give them help without making them try something that fails. WinForms supports these goals in several ways.

Tooltips

One simple way is to provide each control with a tooltip so that when the user hovers the mouse pointer over the control, relevant instructions appear, as shown in Figure 3.6.

Figure 3.6. Using Tooltips

You can use the ToolTip component to add tooltips to any control in a form. After there is a ToolTip component on the form, each control sprouts a new property that shows up as "ToolTip on toolTip1" in the Property Browser. Any new property that an object adds to another object on a form is called an extender property , because the object doing the extending is providing additional functionality to the extended object. [7] Setting the ToolTip extender property for a control gives it a tooltip as provided by the ToolTip component.

[7] Extender properties are covered in detail in Chapter 9: Design-Time Integration.

Using the ErrorProvider for General Information

The problem with tooltips displayed in this way is that the user may not know that they're available (when was the last time you hovered your pointer over a text box looking for help?). Luckily, ErrorProvider is really good at providing a visual indicator, so it could be used with a different icon [8] to show something like Figure 3.7.

[8] We got the sample icon from Common7\Graphics\icons\Computer\W95MBX04.ICO in our VS.NET installation directory. Feel free to use whatever icon makes you happy.

Figure 3.7. Combining the ToolTip Component with the ErrorProvider Component

If you like this kind of thing, it can be implemented using two error providers: one with a friendly information icon, and a second one with a mean error icon (as set using the ErrorProvider's Icon property). The information provider is used when the form is first loaded as well as when there's no error. Otherwise , the error provider is used, as shown here:

 
 Sub LoanApplicationDialog_Load(sender As Object, e As EventArgs) _       Handles MyBase.Load   ' Use tooltips to populate the "information provider"   Dim control As Control   Dim toolTip As String  For Each control In Me.Controls   toolTip = toolTip1.GetToolTip(control)   If toolTip.Length > 0 Then infoProvider.SetError(control, toolTip)   Next  End Sub Sub applicantNameTextBox_Validating(sender As Object, _       e As CancelEventArgs) _ Handles applicantNameTextBox.Validating Dim toolTip As String = toolTip1.GetToolTip(CType(sender, Control))   If CType(sender, TextBox).Text.Length = 0 Then       ' Show the error when there is no text in the text box  errorProvider.SetError(CType(sender, Control), toolTip)   infoProvider.SetError(CType(sender, Control), "")  e.Cancel = True   Else       'Show the info when there is text in the text box  errorProvider.SetError(CType(sender, Control), "")   infoProvider.SetError(CType(sender, Control), toolTip)  End If End Sub 

Just as the ToolTip component adds the ToolTip extender property to each control on the form, the ErrorProvider adds an Error property to each control. Setting a control's Error property in the Property Browser is the equivalent of calling SetError for that control. However, the Error property is not a good place to store a message, because clearing the message is the only way to hide the ErrorProvider for a particular control. Instead, given that the ToolTip property never needs clearing, the example uses it whenever a message should be displayed: when the mouse is hovered over a control, when the information provider is showing, or when the error provider is showing. This has the added benefit of keeping hard-coded strings out of the code and in a place that can easily be made localizable, as discussed in Chapter 10: Resources.

Handling the Help Button and F1

Although the little icons on the forms are useful, you may not want to use this kind of nonstandard interface to provide help messages in your forms. The standard way to provide this kind of information is to use the help button (the question mark) in the upper-right corner of the form, which is enabled by setting the HelpButton property of the form to true. When that button is pressed, the cursor changes, and when the user clicks on a control, the HelpRequested event is fired to the form:

 
 Sub LoanApplicationDialog_HelpRequested(sender As Object, _       hlpevent As HelpEventArgs) Handles MyBase.HelpRequested   Dim controlNeedingHelp As Control   ' Convert screen coordinates to client coordinates  Dim pt As Point = Me.PointToClient(hlpevent.MousePos)  ' Look for control user clicked on   For Each controlNeedingHelp In Me.Controls       If controlNeedingHelp.Bounds.Contains(pt) Then Exit For   Next   ' Show help   Dim help As String = toolTip1.GetToolTip(controlNeedingHelp)   If help.Length = 0 Then Exit Sub   MessageBox.Show(help, "Help")  hlpevent.Handled = True  End Sub 

Notice that the HelpRequested handler uses both of the HelpEventArgs properties:

 
 Public Class HelpEventArgs   Inherits EventArgs   Public Property Handled() As Boolean   Public ReadOnly Property MousePos() As Point End Class 

MousePos is the screen coordinates where the user clicked, and Handled lets us stop the HelpRequested event from going any further if we handle it. In the example, we're converting MousePos, provided in screen coordinates, to client coordinates and walking the list of controls looking for the one the user clicked on. If we find it, we put the control's tooltip into a message box and stop the event from propagating elsewhere.

The help button is useful to most users, but keyboard-oriented Windows users will be more familiar with the F1 key, which is meant to communicate to the application that help is requested on whatever is currently active, which is normally the control with focus. Pressing F1 also results in the HelpRequested event being fired. However, you'll notice that the HelpEventArgs class provides no indication of how the event was fired. So if we want to do something such as open an HTML file when F1 is pressed, we must check whether it was a mouse button that triggered the event:

 
 Sub LoanApplicationDialog_HelpRequested(sender As Object, _       hlpevent As.HelpEventArgs) Handles MyBase.HelpRequested  ' If no mouse button was clicked, F1 got us here   If Control.MouseButtons = MouseButtons.None Then  ' open a help file...  ' Help button got us here   Else  ' show the message box  End If  End Sub 

Because we know that a mouse click triggers the HelpRequested event when it comes from the help button, we need to know whether any mouse buttons were pressed when the HelpRequested event was fired. To do this, we check the Control.MouseButtons property, which provides the state of the mouse buttons during the current event. If no buttons were pressed to fire this event, the user got to the handler using the F1 key; otherwise, they got here using the help button.

Using HTML Help

When you implement F1, it is not hard to launch an URL to show an HTML page. However, when using the help button, users are accustomed to seeing help messages in shadowed tooltips, known as pop-up help , as shown in Figure 3.8.

Figure 3.8. Using HelpProvider to Implement the Help Button

Implementing pop-up help isn't supported by the ToolTip component because it doesn't show shadows and doesn't provide a programmatic way to request that a tooltip to be shown. However, the Help class supports both of these features with the ShowPopup method:

 
 Sub LoanApplicationDialog_HelpRequested(sender As Object, _       hlpevent As HelpEventArgs) Handles MyBase.HelpRequested   If Control.MouseButtons = MouseButtons.None Then       ' open a help file   ' Help button got us here   Else       ' Look for control user clicked on       Dim pt As Point = Me.PointToClient(hlpevent.MousePos)       Dim control As Control       For Each control In Me.Controls           If control.Bounds.Contains(pt) Then  Dim sHelp As String = _   toolTip1.GetToolTip(control)  If sHelp.Length > 0 Then  Help.ShowPopup(Me, _   sHelp, hlpevent.MousePos)  hlpevent.Handled = True                   Exit For               End If           End If       Next   End If End Sub 

The Help class is a wrapper around the HTML Help functions provided by Windows and provides the following interesting methods :

 
 Public Class Help   Public Overloads Shared Sub ShowHelp(parent As Control, _       url As String)   Public Overloads Shared Sub ShowHelp(parent As Control, _       url As String, command As HelpNavigator, param As Object)   Public Overloads Shared Sub ShowHelp(parent As Control, _       url As String, navigator As HelpNavigator)   Public Shared Sub ShowHelpIndex(parent As Control, url As String)   Public Shared Sub ShowPopup( _       parent As Control, caption As String, location As Point) End Class 

The ShowPopup method that we used in the preceding example takes a control to act as a parent, the string to show, and a point, in screen coordinates, on which to center the resulting tooltip. To implement the F1 key by opening an HTML file, you can opt to use one of the ShowHelp functions:

 
 Sub LoanApplicationDialog_HelpRequested(sender As Object, _       hlpevent As HelpEventArgs) Handles MyBase.HelpRequested   ' F1   If Control.MouseButtons = MouseButtons.None Then  Help.ShowHelp(Me, _   Path.GetFullPath("loanApplicationDialog.htm"))  hlpevent.Handled = True   End If   ... End Sub 

Notice that we're using the Path.GetFullPath method (from the System.IO namespace) to turn a relative path name into a full path name . The URL argument to the ShowHelp methods can be a full file path or a full URL, but ShowHelp doesn't seem to like relative path names . Using this technique, F1 will take users to a page of HTML describing the form as a whole. However, users pressing F1 would probably prefer help that is specific to the control that's currently active; in other words, if they press F1 while in the Loan Amount field, they'd like to see help about the Loan Amount field. For that to happen against a file in the local file system requires moving from HTML to Microsoft's compiled HTML Help format.

Compiled HTML Help

When it was clear that HTML files were more flexible than the WinHelp help file format, Microsoft decided to make the switch from WinHelp to something HTML-based. However, WinHelp had a number of advantages over raw HTML, including tools for indexing, searching, and having multiple pages in a single file. The result of merging the flexibility of HTML with the convenience of WinHelp yielded HTML Help, which consists of a set of functions, a set of tools, and a file format that compiles all pages into a single file with a .chm extension. The details of how to build HTML Help files are beyond the scope of this book, so we recommend downloading the HTML Help Workshop from the Microsoft Developer Network site [9] to experiment with it yourself.

[9] http://msdn.microsoft.com

The instructions for creating a minimal HTML Help file with the HTML Help Workshop are as follows :

  1. Run the HTML Help Workshop.

  2. Create a new project. This is the list of files that goes into creating a .chm file.

  3. Create a new HTML file. Add some text to the <body> tag and save the file. This file will become a topic page.

  4. Make sure that the Project tab is selected, and click on the Add/Remove Topic Files button. Add the HTML file you created and saved in step 3. This action adds the topic file to the project.

  5. Click on the Contents tab and choose Create a New Contents File. This enables the table of contents.

  6. Make sure that the Contents tab is selected, and click on the Insert a Page button. Add the HTML file from the previous steps, and make sure that the Entry Title field has a value before pressing OK. This adds an entry to the table of contents.

  7. Click on the Index tab and choose Create a New Index File. This enables the index. Feel free to add a keyword or two to populate the index.

  8. Click on the Project tab again, and click on the Change Project Options button. Choose the Compiler tab. Enable the Compile Full-Text Searching Information option. This enables search.

  9. Compile and view.

When you've got an HTML Help file, you can integrate it into your form using the Help class by passing the name of the .chm file to the ShowHelp function. Furthermore, if you'd like to scroll to a particular subtopic inside a topic, you can do so by first using the HTML <a> tag to name a subtopic:

 
 <!-- loanapplicationdialog.htm --> <html>   <head>     <title>loan application dialog</title>   </head>   <body>     <h1>  <a name="name">Applicant Name</a>  </h1>     Please enter a name.     <h1>  <a name="phoneno">Applicant Phone #</a>  </h1>     Please enter a phone number.     <h1>  <a name="loanamount">Applicant Loan Amount</a>  </h1>     Please enter a loan amount.   </body> </html> 

When you've done that, you can map the name of the subtopic to the control when F1 is pressed:

 
 Sub LoanApplicationDialog_HelpRequested(sender As Object, _       hlpevent As HelpEventArgs) Handles MyBase.HelpRequested   ' F1   If Control.MouseButtons = MouseButtons.None Then       Dim subtopic As String = ""  If Me.ActiveControl Is Me.applicantNameTextBox Then _   subtopic = "name"   If Me.ActiveControl Is Me.applicantPhoneNoTextBox Then _   subtopic = "phoneNo"   If Me.ActiveControl Is Me.applicantLoanAmountTextBox Then _   subtopic = "loanAmount"   Help.ShowHelp(Me, "dialogs.chm", _   "loanApplicationDialog.htm#" & subtopic)  hlpevent.Handled = True   End If   ... End Sub 

Now when F1 is pressed and focus is on a specific control, the topic is brought up in the help viewer window, and the specific subtopic is scrolled into view, as shown in Figure 3.9.

Figure 3.9. Showing the loanAmount Subtopic

However, now that we're back to mapping between controls and strings (subtopics, in this case), this is a perfect use for a component that provides extender properties. The extender properties would allow you to set the help information for each control using the Property Browser, keeping that information out of the code. The component that provides extender properties to manage this information is HelpProvider.

Using the HelpProvider Component

HelpProvider actually implements both topic navigation support for the F1 key and pop-up help for the help button. HelpProvider is a wrapper around the Help class for a specific file, so it works well only for HTML Help. After dropping a HelpProvider component onto your form, you should set its HelpNamespace property to the name of the file it should manage, such as dialogs.chm.

HelpProvider adds the following properties to each control on a form:

 
 Dim HelpKeyword As String 'Defaults to "" Dim HelpNavigator As HelpNavigator ' Defaults to AssociateIndex Dim HelpString As String 'Defaults to "" Dim ShowHelp As Boolean 'Defaults to True 

When F1 is pressed, an empty HelpKeyword results in the HelpString being shown using pop-up help. Otherwise, F1 causes the HelpKeyword to be passed to ShowHelp and used based on the HelpNavigator property, which can be one of the following:

 
 Enum HelpNavigator   AssociateIndex   Find   Index ' What ShowHelpIndex does   KeywordIndex   TableOfContents   Topic ' The default for ShowHelp End Enum 

For example, if HelpNavigator is Topic, then HelpKeyword is the name of the topic to showsay, loanApplicationDialog.htm. ShowHelp is a Boolean that determines whether the HelpProvider should handle the HelpRequested event for the control. Setting ShowHelp to false allows you to handle the HelpRequested event manually, as we've been doing so far.

So after dropping a HelpProvider component onto our sample form, we don't have to handle the HelpRequested event at all. Instead, given the HelpNamespace property set to dialogs.chm, we can set the HelpProvider properties on each control in the form (as shown in Table 3.1). This action causes F1 and the help button to be handled automatically.

Table 3.1. Sample HelpProvider Settings

Control

HelpKeyword

HelpNavigator

HelpString

Show Help

applicantName TextBox

loanApplication Dialog.htm#name

Topic

"Please enter a name"

True

applicantPhone NoTextBox

loanApplication Dialog.htm#phoneNo

Topic

"Please enter a phone number"

True

applicant LoanAmount

loanApplication Dialog.htm#loanAmount

Topic

"Please enter a loan amount"

True

Showing Help Contents, Index, and Search

Dialogs don't often have menuslet alone Help menus with Contents, Index, and Search menu itemsbut while we're on the topic of integrating help with forms, we thought it would be a good idea to mention how to implement these help menu items. You can do this most easily by using the Help class:

 
 Sub helpContentsMenuItem_Click(sender As Object, e As EventArgs) _       Handles helpContentsMenuItem.Click   Help.ShowHelp(this, "dialogs.chm", HelpNavigator.TableOfContents) End Sub Sub helpIndexMenuItem_Click(sender As Object, e As EventArgs) _       Handles helpIndexMenuItem.Click   Help.ShowHelpIndex(this, "dialogs.chm") End Sub Sub helpSearchMenuItem_Click(sender As Object, e As EventArgs) _       Handles helpSearchMenuItem.Click   Help.ShowHelp(this, "dialogs.chm", HelpNavigator.TableOfContents, "") End Sub 


Windows Forms Programming in Visual Basic .NET
Windows Forms Programming in Visual Basic .NET
ISBN: 0321125193
EAN: 2147483647
Year: 2003
Pages: 139

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net