Click here to Skip to main content
15,860,972 members
Articles / Programming Languages / C#

Simple Wizard for WinForms

Rate me:
Please Sign up or sign in to vote.
4.90/5 (13 votes)
17 May 2018CPOL3 min read 85.2K   48   13
A simple wizard

UPDATE: 2018-05-17

This was originally published 8 years ago. Since then, CodePlex has been discontinued. As such, I have moved the code to GitHub for anyone who still finds this useful. Simply click the new download link at the top of this article.

Introduction

SimpleWizard/Capture.PNG

Looking for a quick and simple way to create a wizard host? Look no further. SimpleWizard provides the required interface for your wizard pages, the navigation and even a basic host. A little work is needed on the host, as its UI is rather plain, but the subject of the article is really how to handle the navigation, etc. I'll leave all the prettying up to the readers.

The Interface

C#
public interface IWizardPage
{
   UserControl Content { get; }
   void Load();
   void Save();
   void Cancel();
   bool IsBusy { get; }

   bool PageValid { get; }
   string ValidationMessage { get; }
}

This is the basic requirement: an interface that you can use for your wizard pages. Just create some user controls (the pages), inherit IWizardPage and away you go for that step.

The Collection & Navigation

C#
public enum WizardPageLocation
{
    Start,
    Middle,
    End
}
public class WizardPageCollection : Dictionary<int, IWizardPage>
{
    public IWizardPage CurrentPage { get; private set; }
    public IWizardPage FirstPage { get; }
    public IWizardPage LastPage { get; }

    public WizardPageLocation PageLocation { get; private set; }

    public bool CanMoveNext { get; }
    public bool CanMovePrevious { get; }

    public WizardPageCollection()
    {
        PageLocation = WizardPageLocation.Start;
    }

        public delegate void 
	WizardPageLocationChangedEventHanlder(WizardPageLocationChangedEventArgs e);
    public event WizardPageLocationChangedEventHanlder WizardPageLocationChanged;

    public IWizardPage MovePageFirst()
    public IWizardPage MovePageLast()
    public IWizardPage MovePageNext()
    public IWizardPage MovePagePrevious()

    public int IndexOf(IWizardPage wizardPage)

    public void Reset()

    private void NotifyPageChanged(int previousPageIndex)
}
public class WizardPageLocationChangedEventArgs
{
    public WizardPageLocation PageLocation { get; set; }
    public int PageIndex { get; set; }
    public int PreviousPageIndex { get; set; }
}

Here you can see that I only provided the signatures of the methods, etc. This is for clarity. You can find the actual implementation in the source code at http://simplewizard.codeplex.com/.

For now, to get more of an idea of what is going on in the MovePage...() methods, check out MovePageNext() here:

C#
public IWizardPage MovePageNext()
{
   int previousPageIndex = IndexOf(CurrentPage);

   if (PageLocation != WizardPageLocation.End &&
      CurrentPage != null)
      {
         // Find the index of the next page
         int nextPageIndex = (from x in this
                              where x.Key > IndexOf(CurrentPage)
                              select x.Key).Min();

         // Find the index of the last page
         int lastPageIndex = (from x in this
                              select x.Key).Max();

         // If the next page is the last page
         if (nextPageIndex == lastPageIndex)
         {
            PageLocation = WizardPageLocation.End;
         }
         else { PageLocation = WizardPageLocation.Middle; }

         // Set the current page to be the next page                
         CurrentPage = this[nextPageIndex];
         NotifyPageChanged(previousPageIndex);

         return CurrentPage;
      }
      return null;
}

You'll notice we are inheriting from Dictionary<int, IWizardPage>. The key is the page number and the Value is an IWizardPage. Simply inheriting the aforementioned dictionary takes care of all the collection stuff for us nicely. Now, all we have to care about is navigation.

There are some properties giving you direct access to the current page, first page and last page in the collection, as well as some properties that will tell you whether it is possible to move forward or not and the methods are letting you actually move back and forth through the pages (if possible). The only real place you're going to need any of this is in your host form, which we'll look at in a little while...

I think that sums that up nicely.

Wizard Host

C#
public partial class WizardHost : Form
{
   private const string VALIDATION_MESSAGE = "Current page is not valid. 
	Please fill in required information";

   public WizardPageCollection WizardPages { get; set; }
   public bool ShowFirstButton { get; set; }
   public bool ShowLastButton { get; set; }

   public bool NavigationEnabled { get; set; }

   public delegate void WizardCompletedEventHandler();
   public event WizardCompletedEventHandler WizardCompleted;

   public WizardHost()
   {
      InitializeComponent();
      WizardPages = new WizardPageCollection();
      WizardPages.WizardPageLocationChanged += new 

WizardPageCollection.WizardPageLocationChangedEventHanlder
	(WizardPages_WizardPageLocationChanged);
   }

   void WizardPages_WizardPageLocationChanged(WizardPageLocationChangedEventArgs e)
   {
      LoadNextPage(e.PageIndex, e.PreviousPageIndex, true);
   }

   private void NotifyWizardCompleted()
   private void OnWizardCompleted()
   public void UpdateNavigation()
   private bool CheckPageIsValid()
   public void LoadWizard()
   public void LoadNextPage(int pageIndex, int previousPageIndex, bool savePreviousPage)

   private void btnFirst_Click(object sender, EventArgs e)
   private void btnPrevious_Click(object sender, EventArgs e)
   private void btnNext_Click(object sender, EventArgs e)
   private void btnLast_Click(object sender, EventArgs e)
}

And this is where all the work goes on. Here you have the WizardPageCollection, some properties to choose whether or not to display the First And Last buttons on the wizard (it wouldn't make sense to not show the Next and Previous buttons, which is why only the 2 properties).

All the navigation updates happen here as well as the checks to see whether the current page is valid before moving to the next one. CheckPageIsValid() calls the PageValid property on the IWizardPage. If it returns false, then a message box is shown along with the page's ValidationMessage property.

Again, see the source code for further details.

When you are ready to start your wizard, all you need do is add your wizard pages and show the wizard host as a dialog. Here is an example:

C#
private void button1_Click(object sender, EventArgs e)
{
   WizardHost host = new WizardHost();
   host.Text = "My Wizard";
   host.WizardCompleted += 
	new WizardHost.WizardCompletedEventHandler(host_WizardCompleted);
   host.WizardPages.Add(1, new Page1());
   host.WizardPages.Add(2, new Page2());
   host.WizardPages.Add(3, new Page3());
   host.LoadWizard();
   host.ShowDialog();
}

Conclusion

SimpleWizard allows you to forget about all the navigation issues and simply add your user controls to a WizardHost instance. As simple as that.

History

  • 26th October, 2010: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Freelancer
Australia Australia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionNice work Pin
Mike Hankey22-Aug-23 9:23
mveMike Hankey22-Aug-23 9:23 
QuestionData between wizard pages? Pin
Orbbital26-Feb-14 0:38
Orbbital26-Feb-14 0:38 
AnswerRe: Data between wizard pages? Pin
Member 126294301-Aug-16 6:53
Member 126294301-Aug-16 6:53 
QuestionCould made simpler ? Pin
Tarmo Pikaro12-Oct-13 10:18
Tarmo Pikaro12-Oct-13 10:18 
QuestionVery nice.. Pin
manonthecorner_28-Apr-13 10:07
manonthecorner_28-Apr-13 10:07 
QuestionPassing data between controls Pin
jumbojs8-Jun-12 10:41
jumbojs8-Jun-12 10:41 
GeneralMy vote of 5 Pin
Pietro_SVK27-Apr-11 5:18
Pietro_SVK27-Apr-11 5:18 
GeneralMy vote of 5 Pin
Slash-X5-Nov-10 8:06
Slash-X5-Nov-10 8:06 
GeneralMy vote of 5 Pin
Sivaraman Dhamodharan27-Oct-10 0:47
Sivaraman Dhamodharan27-Oct-10 0:47 
GeneralRe: My vote of 5 Pin
vnmatt28-Oct-10 0:36
vnmatt28-Oct-10 0:36 
QuestionWhy a dictionary, when you're using the collection as a list? Pin
John Brett26-Oct-10 5:22
John Brett26-Oct-10 5:22 
AnswerRe: Why a dictionary, when you're using the collection as a list? Pin
vnmatt26-Oct-10 13:58
vnmatt26-Oct-10 13:58 

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.