Creating a Step-by-Step User Interface with the ASP.NET 2.0 Wizard Control: Improving and Customizing the User Experience
By Scott Mitchell
Introduction
One of the many new Web controls available in ASP.NET 2.0 is the Wizard Web control, which takes the user through a series of discrete steps in order to accomplish some task. As discussed in Creating a Step-by-Step User Interface with the ASP.NET 2.0 Wizard Control: The Basics, the Wizard control is made up of a collection of
<asp:WizardStep>
s,
with each step containing properties (such as its Title
and StepType
) along with HTML and Web controls
specific to that step. The navigational user interface - the Next, Previous, Finish, and Complete buttons that appear at the bottom
of the various steps - are automatically added by the Wizard control and are determined by the step's StepType
property.
In Creating a Step-by-Step User Interface with the ASP.NET 2.0 Wizard Control: The Basics, we examined creating a Wizard control
that broke down the process of adding a new employee to a database into four steps. The first step included instructions;
the second prompted the user for the new employee's first and last name; the third step provided a TextBox and Calendar control
for the employee's salary and hire date; and the final step included the TextBoxes to collect the new employee's contact
information (address, phone, and email). We then created an event handler for the Wizard control's FinishButtonClick
event where we added programmatic logic to insert the new employee record into the database.
While our demo worked, it had a couple of limitations and annoyances, such as not automatically setting focus to the first Web control when moving to a new WizardStep. Furthermore, the demo didn't explore some of the more advanced features of the Wizard control, such as adding a Complete step. Such a step appears after clicking the Finish button and summarizes the action(s) just performed. Additionally, the navigation user interface automatically created by the Wizard can be customized through templates and the sequence of steps can be customized based on user input. In this article we'll see how to accomplish all of these more advanced features. Read on to learn more!
(If you've not yet read Creating a Step-by-Step User Interface with the ASP.NET 2.0 Wizard Control: The Basics, please do so before continuing on with this article...)
Customizing the User Account Creation Process Using the Wizard Control |
---|
ASP.NET 2.0 includes a membership system that makes it a cinch to setup the infrastructure needed to create and manage user
accounts along with a series of user account-related Web controls. The CreateUserWizard control, as its name implies, provides
an interface for a user to create a new account. This control, by default, prompts the user for memebership specific user-related
attributes, such as username, password, email, and so on. However, it can be customized quite easily and broken into a step-by-step
process using the exact same techniques discussed in this article and its precursor.
For more information on customizing the CreateUserWizard control see Erich Peterson's article Customizing the CreateUserWizard Control. For more on ASP.NET 2.0's membership system, check out my article series, Examining ASP.NET 2.0's Membership, Roles, and Profile. |
Improving the User Experience
The Wizard control demo from Creating a Step-by-Step User Interface with the ASP.NET 2.0 Wizard Control: The Basics had a couple usability shortcomings. First off, there was no input field validation. For example, while the
FirstName
field is a required field in the database, the user is able to omit this value, leading to an OleDb-level exception upon
attempting to insert the employee record. We will remedy this 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. (Any additional server-side validation checks can be performed by creating an event handler for the
NextButtonClick
event.)
Another annoyance was that when moving from one step to another, we had 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 in the current wizard step. To set the focus to the first TextBox in the Wizard when moving from one step to the next, we need to do two things:
- Create a method that, given a control, will search its control hierarchy and return the first TextBox control found
- The Wizard's
ActiveStepChanged
event fires each time the user moves from one step to the next. Therefore, we need to add an event handler for this event that searches the current Wizard step's control hierarchy for the first TextBox, using the method created in step 1, and then sets focus to that TextBox
'Recurses through the specified WizardStep's control hierarchy,
|
Then, in the event handler for the Wizard's ActiveStepChanged
event, we get the current WizardStep instance from
the Wizard's ActiveStep
property and pass this control into the FindFirstTextBox
method to find the first TextBox within its control
hierarchy. If a TextBox exists, it's Focus()
method is called, which automatically injects a bit of client-side
JavaScript that causes the TextBox to receive focus on page load (see How to: Set Focus on ASP.NET Web Server Controls
for more information).
Protected Sub AddEmployeeWizard_ActiveStepChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles AddEmployeeWizard.ActiveStepChanged
|
With the FindFirstTextBox
method and ActiveStepChanged
event handler in place, moving from one
Wizard step to another automatically sets focus in the current wizard step's first TextBox (if one exists).
All of the code examined can be downloaded from the end of this article...
Adding a Completed Step
After finishing a wizard, many include a Completed step that summarizes the action(s) performed. For the Add Employee Wizard demo, we might want to include a summary page after the Finish button is clicked that shows the values of the new employee record the user just created. To add a Completed step, simply add a new
<asp:WizardStep>
with its StepType
property set to Complete
.
The following declarative markup adds a Completed step to the Add Employee Wizard demo. This step appears as the last step
in the Wizard and has its StepType
property set to Complete
. The HTML and Web controls within the
step displays summary information, including Label controls that hold the values entered by the user:
<asp:WizardStep runat="server" StepType="Complete" Title="Summary">
|
In the Page_Load
event handler (on each and every postback), the summary's Labels' values are assigned the
values from their respective TextBoxes:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
|
With the Completed step implemented, the previous four steps for the Wizard control remain the same. The user experience is identical up until the Finish button is clicked from the "Employee Contact Information" step. After clicking Finish, the user is displayed the contents of the Completed step.

Customizing the Navigation User Interface
The navigation user interface for the wizard steps are, by default, automatically added by the Wizard control based on the step's
StepType
property. The actual buttons can be rendered as normal Button Web controls, LinkButtons, or ImageButtons,
depending on the value of the Wizard control's *ButtonType
properties (there's the StartNextButtonType
,
FinishPreviousButtonType
, and CancelButtonType
properties). One downside of this auto-generated navigational
user interface is that the Previous button is rendered before the Next button. When displaying these buttons as Button
Web controls (the default), this makes the Previous button the "default button" in the browser, meaning that if a user hits
Enter in a TextBox to submit the form, the Previous button is the one used for submission. The net effect is that with the
default, auto-generated navigational UI, typing in a value into a Wizard TextBox and hitting Enter sends us back to the Previous
step.
The Button Web control in ASP.NET 2.0 provides a UseSubmitBehavior
property that can be used to indicate which Button Web control should have the Submit behavior associated with it. In short,
we can set the Previous button's UseSubmitBehavior
property to False and the Next button's UseSubmitBehavior
to
True; this will mean that hitting enter in a TextBox in the Wizard step will have the same effect as clicking the Next button.
To craft a custom navigational UI, we need to convert the entire Wizard step into an <asp:TemplateWizardStep>
.
The <asp:TemplateWizardStep>
expects two templates:
ContentTemplate
- contains the HTML and Web controls for the step (the markup that was previously declared between the<asp:WizardStep>
and</asp:WizardStep>
tags)CustomNavigationTemplate
- contains the HTML and Web controls for the navigational UI
<asp:WizardStep>
to a
<asp:TemplateWizardStep>
, replace the markup for that step with the following:
|
The ContentTemplate
contains the same markup that was previously found within the <asp:WizardStep>
tags. The CustomNavigationTemplate
includes the Button Web controls for the Next and Previous buttons. Note how
the Previous button's UseSubmitBehavior
property is set to False, while hte Next button's is set to True. Furthermore,
note the CommandName
properties for each button. It's vital that the Previous button's CommandName
be set
to "MovePrevious" and the Next button's to "MoveNext".
With this change, hitting enter from either one of the TextBoxes in the "Employee Name Information" step will send the user to the Next step, as opposed to the previous one. This pattern would need to be repeated for each step in order to have the Enter send the user to the Next step.
One final word on creating a custom navigational user interface - when switching over to templates, the code to programmatically
access a Web control from the ContentTemplate
is different than when accessing Web controls in the <asp:WizardStep>
.
When using the ContentTemplate
, you must use the FindControl("controlID")
approach to reference
a control from within the template, like so:
Dim firstNameTextBox As TextBox
|
In short, with the <asp:TemplateWizardStep>
you lose the direct access to its content Web controls.
Implementing a Custom or Non-Linear Step Sequence
Normally, a wizard proceeds linearly, from the first step to the last. However, it's possible to alter the workflow of the Wizard control based on user input or programmatic logic. In the Add Employee Wizard, the contact information is optional. Therefore, we might want to add a CheckBox in the "Employee Name Information" step with the text, "Specify Contact Information?" If this is checked, the wizard will proceed as normal; however, if it's unchecked, indicating that the user does not want to provide contact information, we can update the "Employee Salary & Hire Date Information" step, setting its
StepType
property to Finish
. This will add a Finish button to the navigational UI for the
"Employee Salary & Hire Date Information" step (and remove the Next button). (Note: if you use a custom navigational UI,
you'll need to manually show/hide the Next and Finish buttons.)
The Wizard control's ActiveStepChanged
event fires after moving from one step to another. Therefore, we can create
an event handler that sets the "Employee Salary & Hire Date Information" step's StepType
based on the
value of the CheckBox in the "Employee Name Information" step.
Protected Sub AddEmployeeWizard_ActiveStepChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles AddEmployeeWizard.ActiveStepChanged
|
This event handler starts by checking if the SpecifyContactInformation
CheckBox (which was added to the
"Employee Name Information" step) was checked or not. If it was, then we want to let the user reach the "Employee Contact
Information" step; therefore, we set the SalaryAndHireDateStep
's StepType
property to Step
.
(I've set the ID
of the <asp:WizardStep>
for the "Employee Salary & Hire Date Information" step
to SalaryAndHireDateStep
.)
If, however, the CheckBox is unchecked, then we want to make the "Employee Salary & Hire Date Information" step the
final step and clear out any values the user might have already entered for the new employee's contact information.
This same concept - creating an event handler for the Wizard's ActiveStepChanged
event - can be used to jump from
one step to another in a non-linear fashion. For example, imagine that we wanted to allow the user to not specify the new employee's
salary and hire date, instead using some pre-canned, default values. Again, we could include a CheckBox in the "Employee Name Information"
step and then, in the ActiveStepChanged
event, we could:
- Check to see if the user has just arrived at the "Employee Salary & Hire Date Information" step
- If so, check to see if the CheckBox to skip the "Employee Salary & Hire Date Information" step has been checked
- If the CheckBox has been checked, then set the Wizard's
ActiveStepIndex
property to the index of the "Employee Contact Information" step
ID
for the "Employee Salary & Hire Date Information" step to SalaryAndHireDateStep
, I've also set the ID
of the "Employee
Contact Information" step to ContactInfoStep
. Also, don't forget that the ActiveStepChanged
event
fires after the Wizard's active step has changed - that's why our check at the start of the following event handler
sees if we're currently at the "Employee Salary & Hire Date Information" step:
Protected Sub AddEmployeeWizard_ActiveStepChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles AddEmployeeWizard.ActiveStepChanged
|
Conclusion
In this article we examined a number of the more advanced features of the ASP.NET 2.0 Wizard Web control, seeing how to improve and customize the user's experience. We saw how to have the first TextBox in a Wizard step receive focus when moving to a new step; we looked at adding a Completed step and customizing the navigational user interface through the use of templates. This article concluded with a look at how to introduce custom and non-linear workflows with the Wizard.
Happy Programming!
Attachments
Suggested Readings