Add Magic to Forms With Wizards

Creating forms to collect user input is one of the most frequently performed tasks in Web application development. The forms that accept the user input are called wizards. These forms must have the plumbing code to handle issues such as state maintenance across postbacks, navigation between forms, and so on. In ASP.NET 1.x, you used Panel and Placeholder controls in one or many ASP.NET pages. ASP.NET 2.0 will ship with a built-in Wizard control that not only automates most of the plumbing tasks for you, but also provides a clean and easy-to-use interface for creating wizard-based applications.

I'll discuss this new Wizard control in depth and demonstrate how to use it to create multiform input pages. Along the way, you'll also learn about the different events, properties, methods, and templates supported by the Wizard control.

Web applications typically include a series of interconnected forms that let users enter input data in a controlled and sequential manner. The Wizard control can go a long way toward simplifying many of the tasks associated with building multiple forms and collecting user input.

You can use the Wizard control to build different forms and customize user navigation without writing a single line of code. The Wizard control lets you collect data in distinct steps, which enables users to navigate between steps at their discretion, thereby creating a simpler user experience. Another important advantage to using the Wizard control: You don't have to worry about issues such as data persistence, state maintenance, and so on, because the Wizard control takes care of these things for you. Each step within a Wizard control can contain one or more of these areas: header, navigation area, sidebar, and body. The sidebar area is optional, and you can control the sidebar display by setting the DisplaySideBar property of the Wizard control to True or False.

The wizard uses steps to differentiate the various sections of user data input. Each step within the control has a StepType that determines whether it's the beginning step, an intermediate step, or a completion step. The wizard can have as many intermediate steps as needed. You can add different controls (such as TextBox or DropDownList) to the wizard steps to collect user input:

Identify the Steps
The Wizard control consists of asp:wizardstep elements that identify the different steps. Each WizardStep template can contain its own set of controls necessary for creating that step of the wizard. The Wizard control can also optionally contain templates such as StartNavigationTemplate and FinishNavigationTemplate, which you can use to configure the different steps of wizard.

The WizardStep template declaration contains an attribute named steptype that can take one of several values: Auto, the default setting; Complete, the last step displayed by the wizard; Start, the first step displayed by the wizard; Step, the intermediate steps displayed between the Start and Finish steps; and Finish, the last step used to collect user input. Note that the Finish value shows only the Previous and Finish buttons, without displaying a Next button. The step after Finish is Complete.

The wizard exposes several key properties (see Table 1). You can also wire up code to handle the various events raised by the wizard: ActiveStepChanged, CancelButtonClick, FinishButtonClick, NextButtonClick, PreviousButtonClick, and SideBarButtonClick. The events themselves are self-explanatory; you have to look only at their names to understand their function. For example, the FinishButtonClick event fires when someone clicks on the Finish button.

Enough background; let's create a simple wizard to display product data from the Microsoft sample Northwind database. Begin by using Visual Studio 2005 to create a new Web site called WizardControl. Once you create the site, add a new Web form named WizardExample.aspx, then drag and drop a Wizard control onto the designer surface. This wizard you create will consist of four steps. The first step displays the category information from the Categories table. Depending on the category selected, the second step displays the products that belong to that category. The third step displays all the details about the product selected in the second step. The fourth step provides a summary of the user selections in the previous steps (see Listing 1 and Figure 1).

Your declarations for the Wizard control are somewhat involved and also consist of four steps. In the first step, the wizard declares a DropDownList control to display all the categories in the Northwind database to the user. The first step also contains a RequiredFieldValidator control to validate whether the user has selected a value in the dropdownlist before navigating to the next step.

The second step is similar to the first step, except that it displays product information rather than category information. The products displayed in the second step are determined by the category selected in the first step. The third step consists of a DetailsView control that you can use to display the details of the selected product, such as QuantityPerUnit, UnitPrice, UnitsInStock, and so on. The fourth step contains a BulletedList control that you can use to display a summary of the user selections in the previous steps. Each WizardStep contains attributes such as ID, Title, and StepType.

Populate the Categories
You use the Page_Load event to populate all the categories in the dropdownlist in the first step of the wizard. Do this by invoking the FillCategories method from within the Page_Load event. The FillCategories method starts by retrieving the connection string from the web.config file. Next, it opens up the connection to the database, then executes the SQL query against the database. Once the results are available in a SqlDataReader object, it sets the DataSource property of the DropDownList object to the SqlDataReader object.

Your next step is to implement the NextButtonClick method, which fires when the user clicks on the Next button in the wizard. This method identifies the current step by examining the CurrentStepIndex property of the WizardNavigationEventArgs object. Depending on the value of the CurrentStepIndex property, the NextButtonClick method invokes either the FillProducts or FillProductDetails methods. As its name suggests, the FillProducts method is responsible for filling the products' dropdownlist with all the products. Similarly, the FillProductDetails method handles populating the products' DetailsView control with all the information about the selected product.

Listing 1 contains the code of the FinishButtonClick event, which fires when the user finally hits the Finish button. You use this event to display the summary of the user selections in previous steps through the use of a BulletedList control.

Next, you need to define the CancelButtonClick event that fires whenever the user clicks on the Cancel button. The code inside this event sets the ActiveStepIndex property of the Wizard control to 0, transferring the control to the first step in the wizard any time the user clicks on the Cancel button during any of the wizard steps.

Note that all the Click events occur before the view change happens, which is indicated by the ActiveViewChanged event. A Click event is the last chance for you to cancel the view change. You might need to cancel the view change when you want to prevent the user from going to the next step because data validation in the current step failed. Note that you can also use a Click event to get more information about the current step and the next step in the wizard by utilizing the CurrentStepIndex and NextStepIndex properties of the WizardNavigationEventArgs object. All Click events except the CancelButtonClick event are passed with the WizardNavigationEventArgs object as its second argument.

So far, you've learned how to take advantage of the Wizard control to create a simple wizard. The next step is to use the wizard to take advantage of the templates supplied with it.

Customize the Wizard Control
The Wizard control supplies five templates you can use to customize it (see Table 2). The Wizard control also supports several styles: CancelButtonStyle, FinishStepButtonStyle, FinishStepPreviousButtonStyle, HeaderStyle, NavigationButtonStyle, NavigationStyle, NextStepButtonStyle, PreviousStepButtonStyle, SideBarButtonStyle, StartStepNextButtonStyle, and StepStyle. You can use these styles to customize the appearance of the various portions of the Wizard control.

Next, you need to modify the code in Listing 1 to support templates and styles. Begin by adding a new Web form named WizardExampleWithTemplates.aspx to the Web site, then copy and paste the code from Listing 1. Next, modify the Wizard control declaration (see Listing 2).

Your modified declaration defines StartNavigationTemplate, FinishNavigationTemplate, and StepNavigationTemplate. StartNavigationTemplate applies to all templates where the step type is equivalent to Start. StartNavigationTemplate contains an ImageButton control to specify the style of the next button. Note that you must set the ID attribute of the ImageButton control to the predefined value of StartNextButton. Similar to StartNavigationTemplate, FinishNavigationTemplate and StepNavigationTemplate also contain ImageButton controls with their ID attributes set to predefined values.

You configure the sidebar links using SideBarTemplate. The main difference between SideBarTemplate and the other templates is that SideBarTemplate requires a DataList control to hold the links. The SideBarTemplate list renders as an HTML table. You utilize the ItemTemplate element of DataList to create custom navigation links. Listing 1 utilizes a Button control to create custom navigation links in the sidebar. After declaring all the templates, you declare styles such as HeaderStyle and SideBarStyle to customize the appearance of the header and sidebar.

The wizard navigation model supports skipping steps or jumping directly to specific steps, thereby enriching the user experience. Also, the wizard's event model gives you fine-grained control over the different forms and the data collected using those input forms.

The wizard-based app described in this article is admittedly simple, but it provides a solid foundation for using the new Wizard control to build wizard-based ASP.NET applications quickly and effectively. Next, you might want to use the wizard-based approach to capture new categories or products from the Northwind database.