Creating a Step-by-Step User Interface with the ASP.NET 2.0 Wizard Control: Improving and Customizing the User ExperienceBy Scott Mitchell
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
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
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
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
FirstNamefield 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
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
ActiveStepChangedevent 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
Then, in the event handler for the Wizard's
ActiveStepChanged event, we get the current WizardStep instance from
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
for more information).
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
StepTypeproperty set to
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:
Page_Load event handler (on each and every postback), the summary's Labels' values are assigned the
values from their respective TextBoxes:
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
StepTypeproperty. The actual buttons can be rendered as normal Button Web controls, LinkButtons, or ImageButtons, depending on the value of the Wizard control's
*ButtonTypeproperties (there's the
CancelButtonTypeproperties). 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
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
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> expects two templates:
ContentTemplate- contains the HTML and Web controls for the step (the markup that was previously declared between the
CustomNavigationTemplate- contains the HTML and Web controls for the navigational UI
<asp:TemplateWizardStep>, replace the markup for that step with the following:
ContentTemplate contains the same markup that was previously found within 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,
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
When using the
ContentTemplate, you must use the
FindControl("controlID") approach to reference
a control from within the template, like so:
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
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.
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
StepType property to
(I've set the
ID of the
<asp:WizardStep> for the "Employee Salary & Hire Date Information" step
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
ActiveStepIndexproperty to the index of the "Employee Contact Information" step
IDfor the "Employee Salary & Hire Date Information" step to
SalaryAndHireDateStep, I've also set the
IDof the "Employee Contact Information" step to
ContactInfoStep. Also, don't forget that the
ActiveStepChangedevent 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:
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.