There are many wizard controls out there: Wizard Control, .NET Wizard control, and of course the magic library. Here's another one, that might meet your needs when others don't.
Last year, I was writing an application that needed a wizard control. I looked around and found none of the controls quite suited my needs, and so I wrote my own. However, following the loss of both the working source code and the CVS tree, I now found myself re-writing from scratch something I have already done once before. The advantage with this method is that my prototype really looked into every single problem that I could have encountered beforehand, and I believe I am left with a nice, neat, and clean result.
It comes in three controls, the first
Wizard handles all the functionality of the wizard, and provides a collection of
WizardPages that you can author upon. Pressing the Back and Next buttons moves through the pages as you would expect (even at design time).
In order to provide the correct look, two additional controls are provided,
Header. These take the correct colors from the
System.Colors namespace and render the expected
Wizard look in lightweight and simple controls. This approach means the GUI can be customized by inheriting or implementing entirely separate controls, and of course, these controls can provide the UI in other forms of your application without needing to use a
One very important point to remember with Wizards is that they are supposed to support a single task and make it easy for an user. It is very easy to add extra features into a Wizard when actually you should split your task into multiple Wizards. Consider that a Wizard can be used to create/edit an object, but not delete it.
v1.1 of this Wizard adds another feature that can be used badly. This is the provision of multiple Finish pages (see below). A Finish page is usually a text only summary of what will happen after Finish is pressed, a last chance to change your mind; however, it can be easier to build this summary on a separate page and have a unique back path.
Using the code
I have subsequently reused this code in several applications; you can either create a DLL or copy it into the same project, whichever your preference.
If you move the code out of the project it is in, you will get three compilation errors:
The type or namespace name 'ParentControlDesigner' could not be found
(are you missing a using directive or an assembly reference?).
These can be easily fixed by adding a reference in the project to the System.Design.dll.
Design Time Features
First, let's have a look at the pretty stuff, via the designer. We will come to real code, event hookup, and manually calling methods, later.
Adding the Wizard to a Form
Once compiled, three controls will be added to your toolbox in user controls. If they don't appear, then you may simply need to open each of them in design mode.
Start by adding a
Wizard control to your form. This one shown below is as dropped on the form and has not been docked or anchored into the form yet.
Please note after first adding that you do not have a control surface to add controls to (as indicated by the lack of a grid inside the control).
Once the page has been added, either change the
Docked property to
Full or set the
Position via the
Adding Pages to the wizard
In order to add pages, go to the
Pages property and click the ellipsis (...) button. This opens the Collection editor which can be used to add pages to the collection. The example comes with three pages already added.
While writing this article, I realize I have not implemented the
RemoveTab verbs for the control. Since a
WizardDesigner is already implemented in this solution, the addition of the verbs and the tying up of the events should be a relatively small piece of work which I shall post up shortly.
WizardPage is an overridden
Panel control, so any other Windows
Control can be dropped straight onto the
WizardPage. This allows you to build up complex Wizard interfaces as you may require; however, this control is currently lacking the standard look of a Wizard as you know it.
Defining a Finish Page
The final page of the Wizard will always be a Finish Page. This means that the Next button will display the word "Finish" and clicking this will return a
Should you design a Wizard that requires multiple different Finish Pages, then additional pages can also become Finish Pages by setting
IsFinishPage=true on the desired
Adding a Wizard Look
The remaining three controls are now used to add the correct look to the Wizard. Start and End pages within the Wizard are handled by using either an
InfoPage contains a full height right docked image, a title and a section of descriptive text. It does not easily support contained controls. The main properties of interest are
Image takes an
image that is the same size as the left image standard system Wizard, i.e., it is 164 pixels wide. However, should your
Form be taller than the image, it will repeat at the bottom. An example image (wizBigOnlineFolder.gif) is included in the project in order that you modify it.
PageTitle is the text which appears in the title section, and
PageText is that which appears below.
InfoContainer is very similar to
InfoPage but only shows a title and image. At its name suggests, it supports contained controls at design time and therefore allows any combination of controls to be added to build up your initial/final page. If the form is Sizable, then I would advise that attention is paid to correctly anchoring contained controls, and that
Vertical are useful instead of labels where a possibly large piece of text is needed to be displayed.
Header is used at the top of every
WizardPage that does not include an
InfoPage. Once again, the interesting properties are the
Image will resize if possible to best fit the image in.
Title is shown in larger font, and
Description the smaller font below.
Both of these controls resize, while attempting to be as accurate to the Wizards used in Windows XP as possible.
This section focuses on the
Wizard control as the others are really only GUI placeholders.
Events raised during Wizard operation
In order to allow the most complicated Wizards to be facilitated, there are five events that are thrown by the
Wizard, four from the
WizardPage and one from the
wizard control throws an event whenever somebody clicks the Cancel button. If you decide to prevent the Close of the Wizard, then set the
Cancel of the
public event CancelEventHandler CloseFromCancel;
Pressing Next or Back, however, raises two events from the
WizardPage, one to close the existing page and another to open the new page.
public event PageEventHandler CloseFromBack;
public event PageEventHandler CloseFromNext;
public event EventHandler ShowFromBack;
public event EventHandler ShowFromNext;
As you can see, the Closing events pass a more complex
eventArgs. The Closing events allow you to override the Next or Previous
Page that will be shown after this
Page closes. The
PageEventArgs provides you with the option of setting the following
Page via either its index (this is not advised for safe code however) or by passing a
public class PageEventArgs : EventArgs
public WizardPage Page [..]
public int PageIndex [..]
CloseFromNext events give the developer a final chance to validate each control on the
WizardPage. Ideally, you have already used an
ErrorProvider to indicate to the User the problems with validation on each control, but during this event, you can double check the values and allow or deny the move to the next
private void wpLogin_CloseFromNext(object sender, Gui.Wizard.PageEventArgs e)
if (<field_1_Validation> == true && <field_2_Validation> == true)
e.Page = wpLogin;
N.B.: I find that writing the logic to check for success is easier to read than checking for a fail. You are free to use DeMorgans Theorem and reverse this to check for a fail should you wish.
Controlling the Wizard Buttons
Wizard also has the ability to enable or disable its buttons depending on your requirements. Since the state of these are expected to change with each page, the state is not saved as part of the design process. They will always default to enabled, and you have the option of disabling them in each
Show event for the page.
public bool NextEnabled [..]
public bool BackEnabled [..]
public bool CancelEnabled [..]
The second page of this example code attempts to demonstrate this with the well known License agreement page. The only code added to the form is as follows:
private void wizardPage2_ShowFromNext(object sender, System.EventArgs e)
wizard1.NextEnabled = checkBox1.Checked;
private void checkBox1_CheckedChanged(object sender, System.EventArgs e)
wizard1.NextEnabled = checkBox1.Checked;
Non-Wizard behavior processing
Finally, there are four methods that have recently been added to the Wizard.
Back() simply allow a programmatic means of going to the following or previous pages respectively. These methods step outside the normal processing of the wizard, so if you can achieve the results you desire via the above methods, I advise you to do so.
Slightly more dangerous are
BackTo(WizardPage). These methods skip raising the
Close event, which of course means that your validation is not performed. My reasoning for this is because the
Close event allows you to specify which page you want to go to. So, if you first tell the Wizard to display a particular page via a call to
NextTo(), and the closing event was called and informs the Wizard to go to a different page, which page should I go to? I have assumed that, as the coder, we understand enough to validate first and only then call
BackTo. An example of this is included in the penultimate page in the demonstration project.
Given, I am issuing the above warning, why should I wish to release these additional methods out to the wild? Well, they solve a couple of unusual circumstances.
The Perform Processing Page and Next() example
On occasions, you wish to display a Wizard page and have it perform processing. When the processing is done, you may wish to change to the next page automatically. (I have unfortunately seen users watch a progress control complete, and then leave a screen sitting there that says 'Press Next to continue...'.)
See the example on the third page of the Wizard to see this in action. (N.B.: the use of the timer is not a very good way of performing processing in the Wizard and receiving updates, but it was simple to code for this example.)
The Button to jump around the Wizard
The final example page has several buttons that allow you to directly access pages in a Wizard. 99% of the time, this can be avoided by setting the
Page property of the
Close event, and I urge you to do so. Please note the difference between using
BackTo compared to any other movement.
One (bad) example where this is of use is, if you are using a Wizard to build a new object and you have to choose something, where different choices then lead to different pages. (It's not a good thing to do, as you have to work out how to navigate back to the correct pages too. Instead, it's better to have one new Form/Wizard to handle selecting which type of object we want to handle, and another Wizard to perform the operation on that Wizard, just like Add Printer in Windows 2000+).
Points of Interest
Using the collection editor
Adding pages caused many problems. The implementation of the
PageCollection and capturing the events is vital in order to work with the VS.NET Collection Editor. If you fail to catch the events, you end up with
Controls that do not get correctly added to the form and frequently are valid only in the code.
Detecting the Next and Back buttons at design time
This also caused many problems and had several work-arounds until I looked at the code behind the other alternative Wizards listed at the start of the article. Thanks go to the authors of these examples (and many others) posted on CodeProject.
This has now been rewritten from scratch. Have a look at the
WizardDesigner for the full code, but it basically works by overloading the
ControlDesigner.GetHitTest to detect where the buttons are, and allow
MouseUp events to be generated.
protected override bool GetHitTest(Point point)
Wizard wiz = this.Control as Wizard;
if (wiz.btnNext.Enabled &&
In the Wizard, we then add handlers for
btnNext and which only work in
private void btnBack_MouseDown(object sender, <BR> System.Windows.Forms.MouseEventArgs e)
if (DesignMode == true)
- v1.1 - 15th Dec 2004. Rewrote to better use Designer features. Now uses
GetHitTest instead of
WndProc. Verified to be compatible with SharpDevelop by user Validate.
- v1.0.1 - 9th Dec 2004. Added multiple finish pages. Not released to CodeProject.
- v1.0 - 15th Nov 2004. Considered stable. (10,000+ page views, 4.54 rating). Update with
InfoContainer, and validation to prevent controls in Wizard (instead of pages) as suggested by user vbnetuk.
- v0.1b - 7th Sep 2004. Fixed the description of
BackTo, and added the main picture.
- V0.1a - 6th Sep 2004. Initial release.