Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Simple Wizard for WinForms

0.00/5 (No votes)
17 May 2018 1  
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

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

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:

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

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:

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here