Click here to Skip to main content
15,391,695 members
Articles / Programming Languages / C#
Posted 5 Sep 2004


311 bookmarked

Designer centric Wizard control

Rate me:
Please Sign up or sign in to vote.
4.91/5 (146 votes)
15 Dec 2004Ms-PL11 min read
A Wizard control designed for design time development.

Sample screenshot


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, InfoPage and 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 Wizard control.

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

ToolBox showing the three controls

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).

Sample form with undocked Wizard

Once the page has been added, either change the Docked property to Full or set the Anchors, Size and Position via the Wizard properties.

Adding Pages to the wizard

WizardPage Collection Editor

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 AddTab and 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.

Each 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 DialogResult.OK.

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 WizardPage.

Adding a Wizard Look

An InfoPage Control

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 or InfoContainer control.

The 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, PageText, and PageTitle. 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.

The 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 RichTextBoxes with BorderStyle=None, ReadOnly=true, Background=White, and Scrollbars=Vertical are useful instead of labels where a possibly large piece of text is needed to be displayed.

Header Control

The Header is used at the top of every WizardPage that does not include an InfoPage. Once again, the interesting properties are the Image, Title, and Description. 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.

Code Features

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.

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 CancelEvent to true.

/// Called when the cancel button is pressed, before the form is 
/// closed. Set e.Cancel to true if 
/// you do not wish to close the wizard.
/// </summary>
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.

/// <summary>
/// Event called before this page is closed when the back button is 
/// pressed. If you don't want to show the next page then set 
/// to be the new page that you wish to show
/// </summary>
public event PageEventHandler CloseFromBack;
/// <summary>
/// Event called before this page is closed when the next button is 
/// pressed. If you don't want to show the previous page then set 
/// to be the new page that you wish to show 
/// </summary>
public event PageEventHandler CloseFromNext;
/// <summary>
/// Event called after this page is shown when the back button is pressed.
/// </summary>
public event EventHandler ShowFromBack;
/// <summary>
/// Event called after this page is shown when the next button is pressed. 
/// </summary>
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 WizardPage itself.

/// <summary>
/// Arguments passed to an application when Page is 
/// closed in a wizard. The Next page to be displayed 
/// can be changed, by the application, by setting 
/// the NextPage to a wizardPage which is part of the 
/// wizard that generated this event.
/// </summary>
public class PageEventArgs : EventArgs
    /// <summary>
    /// Gets/Sets the wizard page that will be displayed 
    /// next. If you set this it must be to a wizardPage 
    /// from this wizard.
    /// </summary>
    public WizardPage Page [..]
    /// <summary>
    /// Gets the index of the page 
    /// </summary>
    public int PageIndex [..]

Page Validation

The CloseFromBack/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 WizardPage.

private void wpLogin_CloseFromNext(object sender, Gui.Wizard.PageEventArgs e)
    if (<field_1_Validation> == true && <field_2_Validation> == true)
        //All successful, do nothing
       //Tell the user Why
       MessageBox.Show("Failed Validation");
       //Stay on the correct page
       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

The 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.

/// <summary>
/// Gets/Sets the enabled state of the Next button. 
/// </summary>
public bool NextEnabled [..]
/// <summary>
/// Gets/Sets the enabled state of the Back button. 
/// </summary>
public bool BackEnabled [..]
/// <summary>
/// Gets/Sets the enabled state of the Cancel button. 
/// </summary>
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. Next() and 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 NextTo(WizardPage) and BackTo(WizardPage). These methods skip raising the WizardPage 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 NextTo or 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 NextTo and 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.

Update (v1.1)

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 MouseDown and MouseUp events to be generated.

protected override bool GetHitTest(Point point)
    Wizard wiz = this.Control as Wizard; 
    if (wiz.btnNext.Enabled && 
        //Next can handle that
        return true; 
    if(wiz.btnBack.Enabled && 
        //Back can handle that
        return true; 
    //Nope not interested
    return false; 

In the Wizard, we then add handlers for MouseDown on btnBack and btnNext and which only work in DesignMode.

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 Next, NextTo, Back, BackTo, and added the main picture.
  • V0.1a - 6th Sep 2004. Initial release.


This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


About the Author

Al Gardner
Software Developer (Senior)
United Kingdom United Kingdom
** Apologies but my daughter was born in October 2004, and so coding now comes second. My reponses tend to take a lot longer**

I've been coding since I got my first ZX Spectrum. From Basic to assembly, through C,C++ and arriving at C#. On the way I've throughly enjoyed Perl, Lisp and XML.

I find I can make the intellectual leap to understand the problem, I love big picture designs, patterns and reuse. I may be addicted to abstract classes Smile | :) GOF has a lot to answer for. I miss delete() even though I spent too much time finding the leaks.

My favourite part of coding is in UI design because of the complexity, the event driven nature, and the fact its (virtually) tactile. I hate GUI's that don't follow system guidelines, don't resize, and don't display properly when you change system colour and font.

Comments and Discussions

QuestionHow can make it so that clicking the FINISH button does not close the window? Pin
Member 768555117-Dec-13 8:50
MemberMember 768555117-Dec-13 8:50 
Questionbug: if you go to last page, then click BACK button, the NEXT button is always a FINISH button Pin
gideon isaac16-Aug-13 1:49
Membergideon isaac16-Aug-13 1:49 
Questionwizard page events don't always work Pin
gideon isaac15-Aug-13 11:04
Membergideon isaac15-Aug-13 11:04 
QuestionNicely done! only needs one more touch to me... Pin
aralmo2-Aug-12 5:29
Memberaralmo2-Aug-12 5:29 
GeneralMy vote of 5 Pin
Sergey Podobry19-May-12 5:20
professionalSergey Podobry19-May-12 5:20 
GeneralMy vote of 5 Pin
tfabraham24-Apr-12 12:39
Membertfabraham24-Apr-12 12:39 
Questioncontrols not showing up in toolbox Pin
Member 836279513-Feb-12 0:59
MemberMember 836279513-Feb-12 0:59 
GeneralMy vote of 5 Pin
HansiHermann4-Feb-12 23:41
MemberHansiHermann4-Feb-12 23:41 
QuestionGood job Pin
Mike Hankey21-Aug-11 7:32
professionalMike Hankey21-Aug-11 7:32 
QuestionDefining page events at design time? Pin
Frank Paynter16-Jun-11 5:47
MemberFrank Paynter16-Jun-11 5:47 
Generalfix for being able to stay on last page Pin
Binkle@JAM4-Mar-11 3:42
MemberBinkle@JAM4-Mar-11 3:42 
GeneralFantastic Pin
davescott24121-Feb-11 16:19
Memberdavescott24121-Feb-11 16:19 
General[Bug] When validating a control Pin
Daniel Nutu5-Oct-10 12:30
MemberDaniel Nutu5-Oct-10 12:30 
GeneralMy vote of 5 Pin
mishrsud29-Sep-10 19:21
professionalmishrsud29-Sep-10 19:21 
GeneralDesign Mode Verbs - Insert Page and Remove Page [modified] Pin
digicate31-Aug-10 22:47
Memberdigicate31-Aug-10 22:47 
QuestionHow about Windows 2008 support Pin
Cory R Stein28-May-10 7:31
MemberCory R Stein28-May-10 7:31 
GeneralThank you! Pin
Mike McLuckie19-Jan-10 10:54
MemberMike McLuckie19-Jan-10 10:54 
QuestionHow to convert this control to custom control? Pin
Guesting22-Dec-09 7:50
MemberGuesting22-Dec-09 7:50 
AnswerRe: How to convert this control to custom control? Pin
Pabinator25-Apr-11 10:19
MemberPabinator25-Apr-11 10:19 
GeneralHelpbutton Pin
leggan21-Dec-09 0:25
Memberleggan21-Dec-09 0:25 
GeneralThank you Pin
ItalianCousin22-Nov-09 4:05
MemberItalianCousin22-Nov-09 4:05 
GeneralOptional Pages with Finish Button Pin
LongPlay24-Jul-09 3:51
MemberLongPlay24-Jul-09 3:51 
QuestionCannot get items in ComboBox to be visible or selectable Pin
primem0ver24-Jun-09 13:43
Memberprimem0ver24-Jun-09 13:43 
Hello Al,

I REALLY appreciate and like what you have done with this wizard. Here is an issue that has me pretty frustrated and I am uncertain where the problem is coming from. I am not a professional programmer so there are some gaps in my understanding sometimes regarding what libraries can interfere with aspect of other libraries, their settings etc. So when I troubleshoot a problem that has no apparent cause (that I can find) I often see if I can duplicate the problem using a single component of my current project. Wala... it works. From there I usually rebuild my application (pasting in/adding my already written code) until I find the problem or somehow manage to rebuild it without one.

However, this project is SO complicated in its use of barely compatible libraries, that it took me a lot of time to find a configuration and application structure that works. (I even had to export all functions that make use of one of microsoft's Vista dependent libraries (that make use of the Virtual Disk Service and other hardware related functions) to an external DLL because I could not get them to function with other components with the /clr option set. The libraries are simply incompatible with managed code).

It is basically a custom computer and network management application that I want to make use of on any computer I purchase in the future. In order to save lots of headache digging through the registry and changing personal settings, I am creating a setup program to make this management system setup easier.

Here is the problem: I am using a combobox for a policy selection box that determines where and how personal folders (such as My documents, my music etc...) will be located and stored. The selections available are dependent on hardware and network resources available to the computer that the manager is being set up on.

No matter what method I use to set up the policy box (even the Designer itself) I cannot get the items in the list to appear or to be selectable. I need it to be dynamic but even a fixed set added using the designer does not work.

The Items GET ADDED and are part of the box's items... for example, if I use the line:
String^ x = RelocationPolicyBox->Items[2]->ToString();
x will be the correct item string. However, they are not being DRAWN and cannot be selected. It is very odd. If I copy the box from the current project to a new project, even on top of one of your wizard pages, it works. I am completely baffled.

If you have any ideas they would be appreciated. TO be honest I am not completely certain it is your library, but I have used combo boxes before and never had this problem and your library is the only thing new when it comes to the UI.

P.S. To save time for the obvious questions: Yes, the combo box is visible and enabled. The items do not show up in the drop down list (is essentially what I mean). I can provide code or send you the entire project when it is clear what you want and how to get it to you.
AnswerRe: Cannot get items in ComboBox to be visible or selectable Pin
Al Gardner28-Jun-09 20:36
MemberAl Gardner28-Jun-09 20:36 
GeneralRe: Cannot get items in ComboBox to be visible or selectable Pin
primem0ver2-Jul-09 15:05
Memberprimem0ver2-Jul-09 15:05 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.