The HTML Help Behaviour

When thinking about Behaviours as “verbs” a number of standard functionalities started to pop into my head. Of these, and one that is missing in WPF, is Help. So I started to think how to integrate HTML Help into WPF and then provide the linkage as behaviours on UIElements. Having searched the web I came across the following two references that neatly encapsulated what I wanted to do.

  1. How to use the unmanaged HTML Help API from a managed Visual C# application
  2. HTML help from within WPF applications

The major hurdle was to catch the F1 and propogate that through tree until a handler could be found. This is a similar situation as to that found with the physics behaviours shown at MIX, i.e. there must be a behaviour attached to the highest element in the tree as well as to those elements that required specific Help access. In essence, then there is only one behaviour and depending on the parameters of the behaviour itself, the behaviour is the general or specific HTML Help handler. Of course, you can configure this differently if you wish, but as we are dealling here with two tree heirarchies, logical tree and help content, it seems logical (at least to me anyway) to handle them so.

As always, I am not going to delve deeply into the code explaining each line in turn. So, in my own style, we will start off with the solution as seen in VS2008.

VS2008 Solution

VS2008 Solution

The complete Behaviour code is as follows:

using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;

namespace HTMLHelpBehaviour
{
    /// <summary>
    /// The <see cref="HTMLHelpBehaviour"/> class.
    /// </summary>
    public class HTMLHelpBehaviour : Behavior<UIElement>
    {
        public static readonly DependencyProperty HelpFileProperty;
        public static readonly DependencyProperty HelpTopicProperty;

        private Help myHelp;

        #region Overrides of Behavior

        /// <summary>
        /// Called after the behavior is attached to an AssociatedObject.
        /// </summary>
        /// <remarks>
        /// Override this to hook up functionality to the AssociatedObject.
        /// </remarks>
        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.KeyDown += AssociatedObjectKeyDown;

            // setup the help linkages
            myHelp = new Help {DefaultHelpFile = HelpFile};
        }

        /// <summary>
        /// Associateds the object key down.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.KeyEventArgs"/> instance containing the event data.</param>
        protected void AssociatedObjectKeyDown(object sender, KeyEventArgs e)
        {
            //do not handle ModifierKeys
            if (Keyboard.Modifiers == ModifierKeys.Shift)
                return;
            if (Keyboard.Modifiers == ModifierKeys.Control)
                return;

            if (e.Key != Key.F1) return;

            // now we have the F1 key pressed in our element
            // check to see if a helpfile has been setup
            if (string.IsNullOrEmpty(myHelp.DefaultHelpFile))
                return;

            if (string.IsNullOrEmpty(HelpFile))
                return;

            // we have a help file - do we have a topic?
            if (string.IsNullOrEmpty(HelpTopic))
                myHelp.ShowHelp();
            else
                myHelp.ShowHelpTopic(HelpTopic);

            // tell the system we handled it, otherwise it will perculate up through the logical tree -
            // which is just what we want when no F1 handler is added
            e.Handled = true;
        }

        /// <summary>
        /// Called when the behavior is being detached from its AssociatedObject, but before it has actually occurred.
        /// </summary>
        /// <remarks>
        /// Override this to unhook functionality from the AssociatedObject.
        /// </remarks>
        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.KeyDown -= AssociatedObjectKeyDown;
        }

        #endregion

        /// <summary>
        /// Initializes the <see cref="HTMLHelpBehaviour"/> class.
        /// </summary>
        static HTMLHelpBehaviour()
        {
            HelpFileProperty =
                DependencyProperty.Register("HelpFile", typeof (string), typeof (HTMLHelpBehaviour),
                                            new UIPropertyMetadata(string.Empty));
            HelpTopicProperty =
                DependencyProperty.Register("HelpTopic", typeof (string), typeof (HTMLHelpBehaviour),
                                            new UIPropertyMetadata(string.Empty));
        }

        /// <summary>
        /// Gets or sets the help file.
        /// </summary>
        /// <value>The help file.</value>
        public string HelpFile
        {
            get { return (string) GetValue(HelpFileProperty); }
            set { SetValue(HelpFileProperty, value); }
        }

        /// <summary>
        /// Gets or sets the help topic.
        /// </summary>
        /// <value>The help topic.</value>
        public string HelpTopic
        {
            get { return (string) GetValue(HelpTopicProperty); }
            set { SetValue(HelpTopicProperty, value); }
        }
    }
}

Within Expression Blend 3.0 you would use the normal “drag and drop” method to attach the Behaviour.

 

  blog3-3

Configuring the HTMLHelp Behaviour in Expression Blend is achived through the properties panel as shown below. Remember to use the full path to the HTMLHelp file.

 blog3-3

The markup within the XAML is as follows:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:HTMLHelpBehaviour="clr-namespace:HTMLHelpBehaviour;assembly=HTMLHelpBehaviour"
    x:Class="HTMLHelpBehaviourTest.Window1"
    Title="Window1"
    Height="300"
    Width="300">
    <i:Interaction.Behaviors>
        <HTMLHelpBehaviour:HTMLHelpBehaviour
            HelpFile="C:\Program Files\Microsoft SDKs\Expression\Blend 3\Help\en\BlendSDK.chm"
             HelpTopic =""/>
    </i:Interaction.Behaviors>
    <Grid>
        <Button HorizontalAlignment="Left"
            Margin="21,0,0,32"
            VerticalAlignment="Bottom"
            Width="105"
            Height="38"
            Content="Button">
            <i:Interaction.Behaviors>
                <HTMLHelpBehaviour:HTMLHelpBehaviour
                    HelpFile="C:\Program Files\Microsoft SDKs\Expression\Blend 3\Help\en\BlendSDK.chm"
                    HelpTopic="Getting started"/>
            </i:Interaction.Behaviors>
        </Button>
        <TextBox Text="TextBox"
            TextWrapping="Wrap"
            Margin="8,8,8,74">
            <i:Interaction.Behaviors>
                <HTMLHelpBehaviour:HTMLHelpBehaviour
                    HelpFile="C:\Program Files\Microsoft SDKs\Expression\Blend 3\Help\en\BlendSDK.chm"
                    HelpTopic="Getting Started"/>
            </i:Interaction.Behaviors>
        </TextBox>

    </Grid>
</Window>

The final result will be a HTMLHelp page when F1 has been pressed on a UIElement.

Advertisements

~ by Intelligence4 on September 3, 2009.

3 Responses to “The HTML Help Behaviour”

  1. Slick! Thanks, this is exactly what I was interested in doing.

  2. Looks very interesting!
    Do you have a reference to a website that demonstrates the functionality?
    (I had a look at your intelligence4 website – fyi there are a number of areas that need to be cleaned from ‘template’ body text that reveals your website was built from a template of some sort…)

    • Hi Borge,

      Sorry, I have no code that will show you the HTML Help code as it was designed for a WPF project that I did some time back. As for the site, yes it was done from a template and since I put it up I have had no real time ti finish it off. Moreover, the development field that it mirrors is no longer my focus. Who knows, maybe sometime soon…… 🙂

Comments are closed.

 
%d bloggers like this: