(Print this page)

A Wiki-based help system
Published date: Friday, February 22, 2008
On: Moer and Éric Moreau's web site

What are the fun parts of our job? If you are a regular reader of my articles, you will surely answer something like writing code, debugging an existing application (yes I like it when I find that one little bug that was so obvious now that we know what it is), building the architecture of the next application, trying newest versions of developers’ tools, and so on.

What do you hate the most? Well your answer may vary but for most of you it would likely be something around the documentation! Am I right?

A long time ago (back in December 2004), I showed you how to build a real help system based on help files that you have to build yourself and link your application to (see Creating help files and linking them to a VB application). Have you built many since that time even if you know how to do it now?

If your users are like mine, they always find that the help files, if you decide to build any, are never complete or up-to-date. This is often because documentation and/or help files are the last thing done in a project and very often you don’t do it because you have to jump on something else.

This month, my column will show you how to save time on the creating help files and ensure that users cannot blame you if those files are not updated. Why not let the users create their own help system and maintain it? This is a very good idea that one of my friend (thanks Nicolas) told me lately. A kind of wiki but still sensitive to the form the users are on.

Because I am using the RichTextBox control, rich text formatting and images are natively supported. Users are also able to copy existing text from an application such as Microsoft Word directly to your RichTextBox control. I am sure they will like it.

I also want the help to be context-sensitive but I don’t want to go to deep. I only want to detect on which I am and display the help related to this form. I don’t want to have a big endless scrolling textbox that user will complain that it is too long.

The basic form

I will start by showing you the form that will be used by users to enter the text as shown in figure 1.

Figure 1: The help form

It is composed of only 3 controls: a ToolStrip, a RichTextBox control, and a checkbox.

The toolbar let the user do usual task such as clear the current text, save the text, cut, copy, paste, change the font of the selected text, and change the color of the selected text. When I have added the ToolStrip control to the form, I used the smart tag actions to insert standard items as a start point. I removed a couple of unwanted buttons (open, print, help) and added a few more (font and font color).

The second control on this form is the RichTextBox control which is the easiest way to let user have a real text editor that allows great features such as pasting content from Microsoft Word.

The last control is a CheckBox that will let the user to use the help form outside the MDIParent form. This is simply done by setting the MdiParent property of the form to Nothing. This is really simple but with more and more users having more than one screen attached to their PC, users start to ask to be able to detach some of the forms from the MDIParent container.

If you need details on how to work with the ToolStrip control, refer to an article I have written on that topic in May 2006 - The Strippers’ club. If you need details on the Font dialog and/or the Color dialog, refer to another article I have written in June 2003 - Common Dialogs.

Persisting data

For this demo, the data entered by user as the help text is persisted into a dataset which is saved as a XML file when the application is closing using the WriteXml method of the dataset object.

This is one thing you will surely want to improve in order to correctly support concurrent users.

I always prefer to save that kind of data into a real database but it would have been harder for you to quickly try this demo application.

When the fMDIParent form loads, the OpenHelpDataset method opens the XML file and loads it into a dataset object or creates a new dataset if the file does not exist:

Private Sub OpenHelpDataset()
    If Not IO.File.Exists("Help.xml") Then
        mHelpDataset = New DataSet

        Dim dt As New DataTable
        With dt
            .TableName = "HelpTable"
            With .Columns
                .Add("Code", GetType(String))
                .Add("HelpText", GetType(String))
            End With
        End With
        mHelpDataset.Tables.Add(dt)
        mHelpDataset.DataSetName = "HelpDataset"
    Else
        mHelpDataset = New DataSet
        mHelpDataset.ReadXml("Help.xml")
    End If
End Sub
When the fMDIParent form is closing, the SaveHelpDataset method is called to save the data entered by the user into the XML file:
Private Sub SaveHelpDataset()
    mHelpDataset.WriteXml("Help.xml")
End Sub
The help form has methods to move data from (see the LoadFormData method) and to (see the SaveData method) this dataset. You will notice that the RTF property of the RichTextBox control is the one used to persist all the formatting. If you use the Text property, all formatting would be lost. You also need to ensure that your field containing the help text into the database is large enough. If you are using Microsoft SQL Server 2005 (or later), you can use the VarChar(MAX) data type.

Integrating the help form into a MDI project

Now that we have our help form almost ready, it is time to integrate it into an application.

You could add a button on each form that creates a new instance of the help form but I will use another method. I will suppose that your application is a MDI application and that your main form has a toolbar and/or a menu (I don’t think that I am off the track here!). In my demo application, I have added a MDI parent which already comes with a menu and a toolbar that I have trimmed a bit.

When the help button or menu item is selected, you need to find which form is currently active in order to display the help that goes with this form. So detecting the active is the first task to do. So I try to find the ActiveMdiChild name, if it is not working, I try the ActiveForm (which would be a standalone form). If neither works, I suppose that no forms are currently opened and force the main help to appear. It is really important to catch exception here because nothing guarantees that a form exists:

Dim strCurrentForm As String = String.Empty
Dim strFormTitle As String = String.Empty

'Try to find a child form
Try
    strCurrentForm = ActiveMdiChild.Name
    strFormTitle = ActiveMdiChild.Text
Catch ex As Exception
    strCurrentForm = String.Empty
End Try

'Try with the active form
If strCurrentForm.Length = 0 Then
    Try
        strCurrentForm = ActiveForm.Name
        strFormTitle = ActiveForm.Text
    Catch ex As Exception
        strCurrentForm = String.Empty
    End Try
End If

'No forms - We are surely on the MDI parent
If strCurrentForm.Length = 0 Then
    strCurrentForm = "Main"
    strFormTitle = "Main form"
End If
Now that we know what is the current form is (which is the key to retrieve the correct help topic), we can display the help form:
Dim f As New fHelp
f.MdiParent = Me
f.LoadHelpForm(strCurrentForm, strFormTitle, mHelpDataset)
f.Show()
Notice that we call the LoadHelpForm method of the fHelp form which is responsible of loading the data from the dataset into the controls.

Figure 2: The demo application in action

Extending this system

I am sure you will have many ideas to enhance this feature even more.

You could start by providing a richer ToolStrip control for editing. Before doing it all by yourself, have a look at what Richard Parsons has posted on the CodeProject web site. It is a wrapper component containing a Toolbar control and a RichTextBox control written in C# that you can plug into your application.

If you build a small table containing the hierarchy of your forms, you could easily show a treeview to let the user navigate between the different help pages.

It would also be nice to be able to print those topics. With the hierarchy of the previous idea, it could be possible to create a table of content and print it in a logical order. If you are interested to try something like this, have a look at Aspose.Words which is a commercial component (meaning not free) that could be very helpful if you want something which is more robust to use then Microsoft Word automation.

Conclusion

Now the pressure is on the users to keep the help system ... helpful and up-to-date. I am sure they will appreciate the fact that they can put their own wording into what THEY used. After all, the help is built for them, why not by them?

I hope you appreciated the topic and see you next month.


(Print this page)