Creating a Step-by-Step User Interface with the ASP.NET 2.0 Wizard Control: The Basics
By Scott Mitchell
Introduction
The wizard - a standard user interface element in desktop applications - takes the user through a series of discrete steps
in order to accomplish some task. A wizard step typically includes instructions, input controls, and an interface for moving
between the wizard's steps (typically Next and Previous buttons, with a Finish button at the last step). Furthermore,
wizards often include different steps depending on the inputs chosen in previous steps.
Wizards have typically been the domain of desktop applications, but have recently become more prevalent in web applications.
In ASP.NET 1.x, developers who wanted to implement a wizard-like user interface would often use multiple Panel Web controls,
one for each Wizard step. As they user progressed through the wizard by hitting the Next and Previous buttons, the appropriate
Panel could be displayed (have its Visible property set to True), while the others hidden (have their Visible
properties set to False).
ASP.NET 2.0 makes creating wizard interfaces a lot less work thanks to its new Wizard control. With the Wizard control, we can
define a series of Wizard steps and specify the content - static HTML and Web controls - that belongs in each step along with
the function of the step, whether it's the first step, one step in the series of steps, the final step, or a summary step
to appear after the wizard has completed. The Wizard control automatically includes the appropriate navigation elements for
each step, remembers the values entered into the Web controls in each step, and includes a rich event model from which programmatic
logic can be added to perform the desired task upon finishing the wizard (among other tasks).
Specifying the Wizard Control's Steps
The Wizard control is useful for breaking down a complex task into a sequence of simpler steps. Each step in the Wizard control
can include the following information:
A Title - along with each step, the Wizard control can optionally include a side bar that lists the available
steps in the wizard and allows the user to quickly jump from one step to another. The title, if provided, is what appears
in the side bar for the step.
A StepType - the navigation controls displayed in each step depend upon the value of the step's
StepType property. This property can be assigned one of the following values:
Start - the Start step includes just a Next button
Step - Step steps include both a Next and Previous button
Finish - the Finish step includes Next, Previous, and Finish buttons
Complete - the Complete step, if provided, displays a summary of the task performed after the
Finish button has been clicked from the Finish step.
Auto - (the default) the navigation controls rendered are automatically determined based on the index of the step itself.
That is, the first step in the wizard is assumed to be the Start step, the last step the Finish step, and all other
steps are considered Step steps; no step is automatically considered a Complete step (if you want a Complete step, it must
be explicitly specified).
Content - each step can be composed of static HTML and Web controls. Often, steps will include Web controls
for collecting user input, which is then used to perform the desired task after the Finish button has been clicked.
When you add a Wizard to an ASP.NET page you can specify the steps through the Designer or directly through the declarative syntax.
From the Designer, click on the Wizard control, then go to the Properties window and scroll down to the WizardSteps
property. Clicking on that property will bring up the WizardStep Collection Editor, from which you can add or remove steps, reorder them,
and alter their properties.
To add content to a step, select the step from the Wizard's smart tag and then simply type in the text or add the Web controls
from the Toolbox that you want to appear in the step.
The steps can also be examined and modified through the declarative syntax. The Wizard control specifies its steps through the
<WizardSteps> element, with each step implemented as an <asp:WizardStep> or
<asp:TemplatedWizardStep>. The Title and StepType properties can be specified
through attributes in the <asp:WizardStep> or <asp:TemplatedWizardStep> tags; the actual
content for the step is placed within the tags.
Creating a Wizard for Inserting a New Record
To illustrate how to use the Wizard control, I've whipped up a demo (which can be downloaded from the end of this article)
that provides a wizard for collecting information that is, at wizard's completion, inserted into a database. In particular,
this demo inserts data into an Access database that has an Employees table; this table has the following schema:
Employees
Column
Data Type
Comments
EmployeeID
AutoNumber
Primary Key / Auto-Increment ID value
FirstName
Text
Required
LastName
Text
Required
Salary
Currency
Required
HireDate
Date/Time
Required
Phone
Text
Optional
Street
Text
Optional
City
Text
Optional
Email
Text
Optional
Rather than having one screen that prompts the user for all of these inputs at once, let's instead have a Wizard control
where each step asks for a subset of the input values. The following screen shots illustrate this goal:
To create such an interface we need a wizard with at least three steps (one for the name information, one for salary and hire date,
and one for the contact information). In addition to these three steps, let's also add an "Introduction" step that includes instructions.
In the "Introduction" step, I have just text (and HTML) explaining the task about to be performed. In the other three steps,
I include Web controls for collecting user input - a Calendar control for the HireDate field and TextBoxes for the other
seven fields.
Let's look at the declarative syntax for this Wizard control. Since it's rather lengthy, let's first just focus on the overall
structure and then dive into each step's content:
I've omitted virtually all style-related markup for brevity. However, I did leave in the Width="95%" setting in the
<asp:Wizard> tag. If you don't set the Width for the entire Wizard control each step's width
will be adjusted based on the content in the step. Therefore, you may want to set the Width of the Wizard control
to some explicit value, either in pixels or as a percentage of the screen width; similarly, you may want to also set the Height
property, if you also want a fixed height.
Note that for each <asp:WizardStep> I've omitted the StepType property. If you omit this property,
the StepType is determined by the ordinal index of the step. Therefore, the "Introduction" step is made a Start step,
the "Contact Information" step a Finished step, and the "Name" and "Salary & Hire Date" steps are made Step steps.
Let's look at the "Name" step's content. Here, I've added two TextBoxes (and an HTML <table> for positioning
purposes) to collect the new employee's FirstName and LastName values.
The other steps include the appropriate markup and Web control syntax to collect the needed input. Note that for each step
we do not need to specify the navigation controls. The appropriate Start, Next, Previous, and Finish buttons are automatically
added based on the step's StepType setting.
Accessing the Content Defined in a Wizard Step
Eventually, after the Finish button has been clicked, we'll need to process the user's input and perform the desired task (in this
case, inserting a record into the Employees table). At this point - or perhaps earlier in the Wizard life cycle -
we may want to programmatically access the values entered by the user into the user controls. This can be accomplished by
referencing the control's directly via their ID values in the code behind class, just like you would had the
controls been defined outside of the Wizard control.
In order to insert a record when the Finished button is clicked, we'll need to do one of two things:
Write ADO.NET code that connects to the database and issues the appropriate INSERT statement,
passing in the values entered by the user in the Web controls
Add an AccessDataSource or SqlDataSource control to the page and specify its InsertCommand property.
We can then use a series of <asp:ControlParameter> values in the InsertParameters collection
to read the values entered by the user and use those values in the actual INSERT statement. With this approach
the only code we have to write is one line - we must invoke the data source control's Insert() method once the
Finish button is clicked.
Let's use the second option (see the Accessing and Updating Data
in ASP.NET 2.0 article series for more information on working with data source controls). The one subtlety here is that
the <asp:ControlParameter> cannot see the controls in the <asp:WizardStep>unless
it's placed within one of the <asp:WizardStep>s. I've put this control in the final step, along with the markup and
Web controls for collecting the user's contact information:
The Wizard Control Event Model
When the user moves from one wizard step to another, the Wizard control raises one or more events. The ActiveStepChanged
event fires anytime one step is about to transition to another. The NextButtonClick and PreviousButtonClick
events fire when the user clicks the Next or Previous button, respectively. The FinishButtonClick event is raised
when the Finish button is clicked.
In this demo we'll only examine one of these events, FinishButtonClick. We'll create an event handler for this
event to insert the employee record. The other events are useful for performing server-side validation of user input or
implementing a non-linear workflow (for example, if, after clicking Next, the Next step depends on the user's input in this
step or a previous one).
The event handler for the FinishButtonClick event for our demo is painfully simply - we just need to invoke the
AccessDataSource control's Insert() method. At that point, the AccessDataSource control will grab the values
from the specified controls and issue the INSERT statement. After inserting the data, the event handler redirects
the user back to the site's homepage.
'This event handler fires when the user clicks Finish. We need to insert the new employee record into the database
Protected Sub AddEmployeeWizard_FinishButtonClick(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.WizardNavigationEventArgs) Handles AddEmployeeWizard.FinishButtonClick
'Insert the employee into the database InsertEmployeeDataSource.Insert()
'Send the user back to the homepage
Response.Redirect("~/Default.aspx")
End Sub
In addition to this event handler, our page also includes a Page_Load event handler that sets the HireDate
Calendar control's SelectedDate property to the current date on the first page load. (You can omit this if you don't
want to Calendar to be set to the current date, by default.)
Limitations of Our Demo
Our demo has some limitations. First off, there's no input field validation. While the FirstName field is a required
field in the database, the user may omit this value, leading to an OleDb-level exception upon attempting to insert the employee record.
This can be remedied using standard ASP.NET validation controls, which will prevent the user from moving to any other step than
the previous one if the validation controls do not report the data as being valid. Also, any additional server-side validation
checks can be performed by creating an event handler for the NextButtonClick event.
Another annoyance is that when moving from one step to another, we have to continuously click in the input field to start entering
data. Ideally, moving to the next screen would automatically place the keyboard's focus in the first input control on the page.
Moreover, you may notice that after entering data into the TextBoxes and hitting Enter, the wizard goes to the previous
step. This is because the Previous button appears before the Next button.
In Creating a Step-by-Step User Interface with the ASP.NET 2.0 Wizard Control: Improving and Customizing the User Experience
we'll see how to overcome these shortcomings. We'll also see how to add a Complete step to the Wizard control
that shows a summary of the action performed. Additionally, we'll see how to use the <asp:TemplatedWizardStep>
control, which allows us to customize the navigation controls for a particular step, as well as how to implement custom and
non-linear progression through the Wizard's steps. (Demos that accomplish these goals are available in the download at the end of this
article.)
Conclusion
Often, it helps to break a complex step into a series of simpler ones. This is the premise behind the wizard, a standard user
interface element that consists of a series of steps and Next, Previous, and Finish buttons that allow the user to progress through
these steps toward accomplishing some larger goal. In an ASP.NET application we can create such a user interface using the
Wizard control.
As we saw in this article, the Wizard control is made up of a number of discrete steps that include the step's title, its
StepType, and content. The StepType property dictates the type of navigation controls the step possesses;
the content for the step includes text and Web controls for processing that step. The Web controls defined within the wizard's
steps can be accessed programmatically like any other control on the page from the ASP.NET page's code-behind class, and are
commonly accessed from the event handler for the Wizard control's FinishButtonClick event.