Context-sensitive help is a kind of online help that is obtained from a specific point in the state of the software, providing help for the situation that is associated with that state. Context-sensitive help, as opposed to general online help or online manuals, doesn't need to be accessible for reading as a whole. Each topic is supposed to describe extensively one state, situation, or feature of the software.
Now the question is how to provide the context sensitive help in a WPF application.
The main idea is to simply use the built-in "ApplicationCommands.Help" command. This command is already tied to the F1 key, and so executes when you hit F1, and tells your command handler what element the user was on when it was hit.
Lets start to create an application in WPF.
| <Windowx:Class="WpfApplication1.Window1" |
| xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
| xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
| Title="Window1"Height="144"Width="300"> |
|
| <GridHeight="70"Width="268"> |
| <Grid.ColumnDefinitions> |
| <ColumnDefinitionWidth="100"MinWidth="32"/> |
| <ColumnDefinitionWidth="175"/> |
| </Grid.ColumnDefinitions> |
| |
| <Grid.RowDefinitions> |
| <RowDefinitionHeight='auto'MinHeight="19"/> |
| <RowDefinitionHeight='auto'MinHeight="31"/> |
| </Grid.RowDefinitions> |
| |
| <TextBlockMargin="0,5,5,0"Height="15"VerticalAlignment="Center">Enteryourname:</TextBlock> |
| <TextBoxGrid.Column='1'Name='NameField'Height="20"VerticalAlignment="Top"Margin="0,0,26,0"/> |
| <ButtonGrid.Row="1"Height="23"Margin="15,8,85,0"Name="Submit"VerticalAlignment="Top"Grid.Column="1">Submit</Button> |
| </Grid> |
| </Window> |
Now we have a sample application with a test box and a button.
Now lets add a help provider class in the sample application.
You will need to add the reference of " System.Windows.Forms" in the sample application.
| staticclassHelpProvider |
| { |
| publicstaticreadonlyDependencyPropertyHelpStringProperty= |
| DependencyProperty.RegisterAttached("HelpString",typeof(string),typeof(HelpProvider)); |
|
| staticHelpProvider() |
| { |
| CommandManager.RegisterClassCommandBinding(typeof(FrameworkElement),new |
| CommandBinding(ApplicationCommands.Help,newExecutedRoutedEventHandler |
| (Executed),newCanExecuteRoutedEventHandler(CanExecute))); |
| } |
|
| publicstaticvoidSetHelpString(DependencyObjectobj,stringvalue) |
| { |
| obj.SetValue(HelpStringProperty,value); |
| } |
|
| |
| staticprivatevoidCanExecute(objectsender,CanExecuteRoutedEventArgse) |
| { |
| FrameworkElementsenderElement=senderasFrameworkElement; |
| if(HelpProvider.GetHelpString(senderElement)!=null) |
| e.CanExecute=true; |
| } |
|
| publicstaticstringGetHelpString(DependencyObjectobj) |
| { |
| return(string)obj.GetValue(HelpStringProperty); |
| } |
|
| staticprivatevoidExecuted(objectsender,ExecutedRoutedEventArgse) |
| { |
| System.Windows.Forms.MessageBox.Show("Help:"+HelpProvider.GetHelpString(sender |
| asFrameworkElement)); |
| } |
|
| } |
|
Instead of putting the command handler in the Window, we'll put it in the HelpProvider itself. We can do this by registering a command handler directly against the FrameworkElement class; now we'll get called for any FrameworkElement instance in the application. We'll also register for the command's CanExecute handler. This allows us to decide if we should handle a command at an element, or let it bubble up to a higher handler. That is, this will allow the Help command to bubble up from AddressField, which has no HelpString, to Window which does.
Now lets add some help text to the text box and the button.
| <Windowx:Class="WpfApplication1.Window1" |
| xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
| xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
| Title="Window1"Height="144"Width="300" |
| xmlns:h="clr-namespace:WpfApplication1"> |
|
| <GridHeight="70"Width="268"> |
| <Grid.ColumnDefinitions> |
| <ColumnDefinitionWidth="100"MinWidth="32"/> |
| <ColumnDefinitionWidth="175"/> |
| </Grid.ColumnDefinitions> |
| |
| <Grid.RowDefinitions> |
| <RowDefinitionHeight='auto'MinHeight="19"/> |
| <RowDefinitionHeight='auto'MinHeight="31"/> |
| </Grid.RowDefinitions> |
| |
| <TextBlockMargin="0,5,5,0"Height="15"VerticalAlignment="Center">Enteryourname:</TextBlock> |
| <TextBoxGrid.Column='1'Name='NameField'Height="20"VerticalAlignment="Top"Margin="0,0,26,0" |
| h:HelpProvider.HelpString="Enteryourname."/> |
| <ButtonGrid.Row="1"Height="23"Margin="15,8,85,0"Name="Submit"VerticalAlignment="Top" |
| Grid.Column="1"h:HelpProvider.HelpString="Presssubmitbuttontosave.">Submit</Button> |
| </Grid> |
| </Window> |
Now press F1 on NameField displays "Enter your name.", and F1 on the Submit button displays "Press submit button to save.".
Finally, note that you can also do more exciting things in the help handler, like load a chm file with the System.Windows.Forms.Help class.
Finally, note that you can also do more exciting things in the help handler, like load a chm file with the System.Windows.Forms.Help class. You can also load the chm or html file from the xaml by specifying the path of the file. h:HelpProvider.HelpString="MyHelp.chm"
| staticprivatevoidExecuted(objectsender,ExecutedRoutedEventArgse) |
| { |
| System.Windows.Forms.Help.ShowHelp(null,@"MyHelp.chm"); |
| } |
| Now the class will look like this.
| staticclassHelpProvider |
| { |
|
| publicstaticreadonlyDependencyPropertyHelpStringProperty= |
| DependencyProperty.RegisterAttached("HelpString",typeof(string),typeof(HelpProvider)); |
|
|
| staticHelpProvider() |
| { |
| CommandManager.RegisterClassCommandBinding(typeof(FrameworkElement),new |
| CommandBinding(ApplicationCommands.Help,newExecutedRoutedEventHandler |
| (Executed),newCanExecuteRoutedEventHandler(CanExecute))); |
| } |
|
| publicstaticvoidSetHelpString(DependencyObjectobj,stringvalue) |
| { |
| obj.SetValue(HelpStringProperty,value); |
| } |
|
|
| staticprivatevoidCanExecute(objectsender,CanExecuteRoutedEventArgse) |
| { |
| FrameworkElementsenderElement=senderasFrameworkElement; |
| if(HelpProvider.GetHelpString(senderElement)!=null) |
| e.CanExecute=true; |
| } |
|
| publicstaticstringGetHelpString(DependencyObjectobj) |
| { |
| return(string)obj.GetValue(HelpStringProperty); |
| } |
|
| staticprivatevoidExecuted(objectsender,ExecutedRoutedEventArgse) |
| { |
| Help.ShowHelp(null,HelpProvider.GetHelpString(senderasFrameworkElement)); |
| } |
| } |
|
| I hope this post made life a little easier.
- Edited byNiraj Singh Thursday, September 04, 2008 12:20 PMformatting was not proper
-
| | Niraj Singh | This is good and all, but you could have mentioned that this is a copy-paste post from Mike Hillberg
Dependency Visualizer - http://www.codeplex.com/dependencyvisualizer | | Simon Dahlbacka | We've cribbed this code in our application and it works fine under Mozilla Firefox. Hit F1 and the desired page of the help file appears in a new window.
However, when we run under Internet Explorer, something odd happens. Sure, our context-sensitive help appears as it ought, BUT so does the Internet Explorer's help file. Don't want this. Seems that the F1-generated help gets handled by Internet Explorer before our application gets the event and displays its own help window.
Setting e.Handled = true in the delegate I registered doesn't help because (i think) Internet Explorer has gotten in line ahead of us.
| | StevePoling |
|