Click here to Skip to main content
11,580,926 members (64,333 online)
Click here to Skip to main content

Simple Wizard for WinForms

, 26 Oct 2010 CPOL 30.8K 33
Rate this:
Please Sign up or sign in to vote.
A simple wizard
Capture.PNG

Introduction

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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

vnmatt
Software Developer (Senior) Freelancer
Vietnam Vietnam
No Biography provided

You may also be interested in...

Comments and Discussions

 
QuestionMessage Automatically Removed Pin
1-Apr-14 16:42
memberMember 102217411-Apr-14 16:42 
QuestionData between wizard pages? Pin
Orbbital26-Feb-14 0:38
memberOrbbital26-Feb-14 0:38 
QuestionCould made simpler ? Pin
Tarmik12-Oct-13 10:18
memberTarmik12-Oct-13 10:18 
QuestionVery nice.. Pin
holyburak28-Apr-13 10:07
memberholyburak28-Apr-13 10:07 
QuestionPassing data between controls Pin
jumbojs8-Jun-12 10:41
memberjumbojs8-Jun-12 10:41 
GeneralMy vote of 5 Pin
Pietro_SVK27-Apr-11 5:18
memberPietro_SVK27-Apr-11 5:18 
GeneralMy vote of 5 Pin
Slash-X5-Nov-10 8:06
memberSlash-X5-Nov-10 8:06 
GeneralMy vote of 5 Pin
sirama200427-Oct-10 0:47
membersirama200427-Oct-10 0:47 
GeneralRe: My vote of 5 Pin
gordon_matt28-Oct-10 0:36
membergordon_matt28-Oct-10 0:36 
QuestionWhy a dictionary, when you're using the collection as a list? Pin
John Brett26-Oct-10 5:22
memberJohn Brett26-Oct-10 5:22 
AnswerRe: Why a dictionary, when you're using the collection as a list? Pin
gordon_matt26-Oct-10 13:58
membergordon_matt26-Oct-10 13:58 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150603.1 | Last Updated 26 Oct 2010
Article Copyright 2010 by vnmatt
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid