Click here to Skip to main content
Click here to Skip to main content

Wizard Tab Control

, 11 Oct 2002
Rate this:
Please Sign up or sign in to vote.
A wizard control for .NET

MFC Updating Status Bar Automatically

Introduction

Unfortunately, Microsoft didn't include a wizard for us in .NET, nor do I see any plans to implement one before late 2003, so it's necessary for us to create a work around that is both elegant and flexible.

I want to first off give James Johnson credit for inspiring me to write a wizard control and post it for you here on CodeProject.  Although his solution is a very usable, I didn't find it as elegant as I wished.  It used the standard model of having multiple pages separated into multiple files, and if your system is like mine, the toolbox started to get quite crowded with inherited controls.  Thanks James for taking up precious time to give us a solution.  I based my example off of his sample, so it might look a tad like his.

Traditionally wizards were created from property pages/sheets with a few additional buttons and setting SetWizardMode for turning off the tabs.   I tend to like both a next/finished button instead of renaming the next button on the last step.  If there are circumstances where I can finish up a wizard early, then the single button approach has no solution.

Problems

Well, we don't have SetWizardMode anymore!  Nor can we turn off the tabs from appearing on the property sheets!!  That created a big problem in trying to make a property sheet based wizard functional.  But, the property sheets became incredibly more powerful with the ability to work on all the pages simultaneously. 

So, I cheated...

Solution

The first thing I had to do was turn off those darn tabs!! After months of searching, I didn't get too far with any type of solution.  I pray that someone has a better solution than this.  Then I can come back and edit it as fast as possible to hide what I did.

I created a simple control called EtchedLine.  It's actually a decent little control that draws a simple line the width of the control.  Then whenever the base form is resized, I moved the EtchedLine over onto the top of the tab control.  I changed the drawing property of the control to draw a white line on the bottom of itself to completely hide where the tabs were and to make it look like one continuous window.  Quit laughing.

private void InitializeEtchedLine( ) 
{ 
   if( this.DesignMode ) 
   {
      lblEtchedLine.Size = new Size ( 10, 10 ); 
      lblEtchedLine.Location = new Point( 10, Height - 10 ); 
   } 
   else 
   { 
      lblEtchedLine.Size = new Size( WizardControl1.Width - 1, 
                                     WizardControl1.DisplayRectangle.Y - 1 ); 
      lblEtchedLine.Location = WizardControl1.Location; 
   } 
}
       

WizardControl

Once I was allowed to use the property sheets, the WizardControl began to evolve nicely.  I have written a base form named WizardForm that completely encompasses the entire control.  So don't worry about having to access any of the WizardControl properties directly.

Properties

  • NextButton - The form's next button.  The control will enable/disable the button when appropriate
  • BackButton - The form's back button
  • CancelButton
  • FinishedButton
  • TitleLabel - The main title of the page.  The control will update the title depending on the step.
  • AllowBack - Allows the user to use the back button to edit their previous choices

Methods

  • MoveBack - Step back one page
  • MoveNext - Step forward one page
  • MoveFirst - Go to the first page and initialize itself
  • MoveTo - Go to a specific index or page
  • HideStep - Hide a step from the standard page order
  • ShowStep - Show a hidden step in the standard page order

Events

  • Event_Initialize - When the wizard is first initialized.  Reset/set any options here.
  • Event_MoveNext - Next button has been pressed.  Override to validate the page.
  • Event_MoveBack - Previous button has been pressed.
  • Event_PageChanged - Page has changed to this current page.  Override to initialize variables
  • Event_Cancelled - Cancel button was pressed.  Override to warn if appropriate.
  • Event_Finished - Finish button was pressed.  Override to validate all of the data on the form.

WizardTabPage

You will be adding pages to the WizardControl the exact same way that you would be adding pages to a TabControl. 

Important: Once you have added a TabPage to your control, you will currently need to edit the source code and change all occurrences of TabPage to the WizardTabPage.  I'm sure there's some way of doing that automatically through an attribute, and if you find out how, please let me know!

this.tabPage2 = new WizardTab.WizardTabPage();

Properties

  • Title - The text that you would like to show on the top of the page.
  • ShowFinished - Show the finished button on this page regardless if it's the last page or not.
  • Hidden - Hide this property page based on user decisions.

You can change the properties of the tab page directly either through the Property settings or through the TabPages property in the WizardControl.

WizardForm

And the last piece of the wizard is the form that you will be using to inherit from.

Important: To initialize the page correctly, we need to add a MoveFirst to your base class right after the data is initialized.  This will initialize your next/prev buttons correctly.

public OrderPizza( )
{
   InitializeComponent( );
   this.WizardControl1.MoveFirst( );
}

Virtual Functions

  • OnWizInitialize
  • OnWizMoveNext
  • OnWizMoveBack
  • OnWizPageChanged
  • OnWizCancelled
  • OnWizFinished 

Inheriting from WizardForm

Ok, you're ready to add a wizard to your project.

  1. Add WizardControl and EtchedLine to your toolbar.
  2. Add an Inherited Form and derive from WizardTab.WizardForm.
  3. Add additional pages by modifying the control's TabPages .
  4. Don't forget to rename all TabPages WizardTabPages in the source code.
  5. Add MoveFirst after your InitializeComponents function in your main class.

That's really about it!!

Validating Pages

To validate the data on the page, override the OnWizMoveNext function.  Put any type of validation that you wish and pass eCancel.Cancel = false if you want to prevent the user from continuing.

protected override void OnWizMoveNext( WizardTab.WizardControl pWizard, 
                                       WizardTab.WizardTabPage pTabPage, 
                                       CancelEventArgs eCancel )
{ 
   switch( pWizard.SelectedIndex )
   {
   case 1: 
      if( this.chkAnchovies.Checked ) 
      { 
         MessageBox.Show( "We've never actually had anchovies. It's just something " +
                          "we've always put on our menu", "Sorry, no anchovies" ); 
         eCancel.Cancel = true; 
      } 
      
      if( this.chkBacon .Checked == false && this.chkMushrooms.Checked == false &&
          this.chkOnions.Checked == false && this.chkPepperoni.Checked == false ) 
      { 
         MessageBox.Show( "You've got to put something on your pizza, that just ain't " +
                          "American", "What? No toppings?!" ); 
         eCancel.Cancel = true; 
      } 
      
      break; 
      }
      
   return; 
}

Using the Data

What's really nice about this solution is that all of your variables are accessible in your functions.  All of the variables on your pages can be accessed directly without the need to pass your variables via a parent object or through function parameters.

protected override void OnWizPageChanged( WizardTab.WizardControl pWizard, 
                                          WizardTab.WizardTabPage pTabPage )
{
    switch( pWizard.SelectedIndex )
    {
    case 3:

    StringBuilder strOrder = new StringBuilder( );

    strOrder.Append( "Crust: \r\n" );

    if( this.btnThickCrust   .Checked ) 
        strOrder.Append( "\tThick Crust\r\n" );
    if( this.btnThinAndCrispy.Checked ) 
        strOrder.Append( "\tThin and Crispy\r\n" );
    if( this.btnChicagoStyle .Checked ) 
        strOrder.Append( "\tChicago Style Deep Dish\r\n" );

    strOrder.Append( "\r\nToppings: \r\n" );

    if( this.chkPepperoni.Checked )
        strOrder.Append( "\tPepperoni\r\n" );
    if( this.chkBacon    .Checked )
        strOrder.Append( "\tCanadian Bacon\r\n" );
    if( this.chkMushrooms.Checked )
        strOrder.Append( "\tMushrooms\r\n");
    if( this.chkOnions   .Checked )
        strOrder.Append( "\tOnions\r\n" );

    this.textBox1.Text = strOrder.ToString( );

    break;
    }
}

Conclusion

I hope that I've included enough flexibility that you find this Wizard a superior solution to the old MFC wizards that we're all familiar with.   Let me know if there is more functionality that you would like to see.

Oh yea, The Pizza Hut name, logos, and related marks are trademarks of Pizza Hut, Inc.

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

Share

About the Author

Zombies with Coffee, LLC
Founder Zombies With Coffee, LLC
United States United States
Phillip has been a programmer long enough to remember cutting paper strip code out of Dr. Dobbs and running them thru a mechanical decoder to avoid typing in the samples.
Follow on   Twitter

Comments and Discussions

 
QuestionHow to avoid keyboard change? PinmemberJicin24-Feb-10 4:32 
AnswerRe: How to avoid keyboard change? PinmemberJicin24-Feb-10 5:41 
GeneralHide Tabs Pinmembertbushell31-May-09 19:40 
GeneralPizza Hut PinmemberStringDotEmpty22-Mar-09 21:14 
Generalhiding tabs Pinmemberpeetba29-Apr-04 2:55 
GeneralRe: hiding tabs Pinmemberklarat7829-Apr-04 5:16 
GeneralRe: hiding tabs [modified] PinmemberWimpie Ratte21-Apr-08 5:29 
GeneralRe: hiding tabs PinmemberSSDiver211218-Mar-10 20:02 
I still got the "bump" with this.
Try this it works better.
 
TabControl1.Region = _
New Region(New RectangleF(Me.TabPage1.Left, Me.TabPage1.Top, Me.TabPage1.Width, Me.TabPage1.Height))
 
SSDiver2112
GeneralNot much Wizardry... Pinmemberrajbow27-Feb-04 5:40 
GeneralRe: Not much Wizardry... Pinmemberpsdavis27-Feb-04 7:32 
Generalnavigation buttons not complete showing PinmemberTheresa Ruby17-Feb-04 11:50 
GeneralRe: navigation buttons not complete showing Pinmemberpsdavis18-Feb-04 2:41 
GeneralRe: navigation buttons not complete showing Pinmemberrajbow27-Feb-04 5:58 
GeneralScreen dump missing PinmemberZitchbow11-Nov-03 4:58 
GeneralRe: Screen dump missing Pinmemberpsdavis11-Nov-03 4:59 
GeneralThe tabs aren't visible Pinmembermwherman200020-Oct-03 17:53 
GeneralRe: The tabs aren't visible Pinmembermwherman200020-Oct-03 18:06 
GeneralRe: The tabs aren't visible Pinmemberpsdavis21-Oct-03 3:11 
QuestionMS Wizard control in late 2003? PinmemberSascha Andres18-Aug-03 3:05 
AnswerRe: MS Wizard control in late 2003? Pinmemberpsdavis18-Aug-03 3:34 
GeneralAn error when trying to use Pinmemberspdeegan@earthlink.net18-Jun-03 5:11 
GeneralWizard control event PinmemberDeepkiss4-Jun-03 5:27 

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 | Mobile
Web04 | 2.8.141015.1 | Last Updated 12 Oct 2002
Article Copyright 2002 by Zombies with Coffee, LLC
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid