Click here to Skip to main content
15,885,767 members
Articles / Web Development / ASP.NET

Hands-on Navigation for ASP.NET Web Forms - Part 1

Rate me:
Please Sign up or sign in to vote.
3.00/5 (2 votes)
10 May 2010CPOL5 min read 18.6K   251   11  
Implementation of a Web UI Wizard using the Navigation for ASP.NET Web Forms framework

Introduction

This article illustrates how to implement a Web UI Wizard using the open source Navigation for ASP.NET Web Forms project, located at http://navigation.codeplex.com. The standard ASP.NET approach would be to use a Wizard control and define the WizardSteps. This can lead to one large, unmaintainable aspx Page. The Navigation for ASP.NET Web Forms framework allows each step to be its own aspx Page. The framework manages all the navigation and data passing between these steps. This leads to small, maintainable aspx pages with (almost) empty code-behinds.

Background

Navigation for ASP.NET Web Forms is an open source project, located at http://navigation.codeplex.com, that handles navigation and data passing between aspx pages. This article goes straight into using this framework without explaining it and so assumes a familiarity with the project's documentation.

Using the Code

This article walks through the creation of a Wizard navigation with three steps. The first step collects the user's title and gender; the second step collects the user's name and age indicator; and the third step summarises the user's selections. The sample code is written in VS 2008, although the Navigation for ASP.NET Web Forms project works in VS 2005 or later - the relevant binary for the version of the .NET framework in use can be downloaded from http://navigation.codeplex.com.

Start by creating a new Web Site called WizardNavigation and set it up to use the Navigation for ASP.NET Web Forms framework by registering the StateAdapter class as an adapter for the Page control (see the Getting Started section of http://navigation.codeplex.com/documentation).

Next the Dialogs, States and Transitions, that make up the State Information configuration, must be defined. Each step represents a separate State, since each is its own aspx Page, and these will be called Step1, Step2 and Summary. The transitions are straightforward, as each step must be able to Navigate to the next step, and so there is one from Step1 to Step2 and one from Step2 to Summary. This configuration is shown below:

XML
 <dialog key="Wizard" initial="Step1" path="~/Step1.aspx">
	<state key="Step1" page="~/Step1.aspx" title="Step 1">
		<transition key="Next" to="Step2"/>
	</state>
	<state key="Step2" page="~/Step2.aspx" title="Step 2">
		<transition key="Next" to="Summary"/>
	</state>
	<state key="Summary" page="~/Summary.aspx" title="Summary">
	</state>
</dialog>

To the Web Site, add a Page called Step1.aspx. To Step1.aspx, add a FormView bound to a NavigationDataSource (see the Data Binding section of http://navigation.codeplex.com/documentation) and containing a Title DropDownList and a Gender RadioButtonList (both with an associated RequiredFieldValidator) and an Update Button. The SelectedValue properties of the DropDownList and RadioButtonList are set using the 2-way databinding syntax. The code for Step1.aspx is shown below:

ASP.NET
 <asp:FormView ID="FormView1" runat="server" 
	DataSourceID="NavigationDataSource1" DefaultMode="Edit">
	<EditItemTemplate>
		<div><asp:Label ID="Label1" runat="server" 
		Text="Title" AssociatedControlID="DropDownList1" />
		<asp:DropDownList ID="DropDownList1" runat="server" 
			SelectedValue="<%# Bind('[title]') %>">
			<asp:ListItem Text="" />
			<asp:ListItem Text="Mr" />
			<asp:ListItem Text="Ms" />
			<asp:ListItem Text="Miss" />
			<asp:ListItem Text="Mrs" />
		</asp:DropDownList>
		<asp:RequiredFieldValidator ID="RequiredFieldValidator1" 
			runat="server" ControlToValidate="DropDownList1" 
			EnableClientScript="False" 
			ErrorMessage="Please select a Title" /></div>
		<div><asp:Label ID="Label2" runat="server" 
			Text="Gender" AssociatedControlID="RadioButtonList1" />
		<asp:RadioButtonList ID="RadioButtonList1" 
			runat="server" SelectedValue="<%# Bind('[gender]') %>" 
			RepeatDirection="Horizontal">
			<asp:ListItem Text="Male" />
			<asp:ListItem Text="Female" />
			<asp:ListItem Text="Blank" />
		</asp:RadioButtonList>
		<asp:RequiredFieldValidator ID="RequiredFieldValidator2" 
			runat="server" ControlToValidate="RadioButtonList1" 
			EnableClientScript="False" 
			ErrorMessage="Please select a Gender" InitialValue="Blank" />
			</div>
		<asp:Button ID="Button1" runat="server" Text="Next" 
			CommandName="Update" />
	</EditItemTemplate>
</asp:FormView>
<cc1:NavigationDataSource ID="NavigationDataSource1" runat="server">
</cc1:NavigationDataSource> 

Setting Step1.aspx as the start page and pressing F5 will result in the error "RadioButtonList1 has a SelectedValue which is invalid because it does not exist in the list of items." This is because the SelectedValue is databound to the StateContext Data item with key 'gender' which starts out with a null value which, as the error says, is not in the list of items. The SelectParameters of the NavigationDataSource can fix this as these are used to initialize StateContext Data items. So, to initialize the StateContext Data item with key 'gender' to a valid list item value, add the SelectParameter shown below:

ASP.NET
<cc1:NavigationDataSource ID="NavigationDataSource1" runat="server">
	<SelectParameters>
		<cc1:NavigationDataParameter Name="gender" DefaultValue="Blank"/>
	</SelectParameters>
</cc1:NavigationDataSource> 

This time, pressing F5 will show the Step1.aspx page.

To the Web Site, add a Page called Step2.aspx and set it up in much the same way as shown for Step1.aspx, this time with a Name TextBox and an Over 18 CheckBox indicator. The code for Step2.aspx is shown below:

ASP.NET
 <asp:ListView ID="ListView1" runat="server" 
	DataSourceID="CrumbTrailDataSource1" ItemPlaceholderID="PlaceHolder1">
	<LayoutTemplate>
		<asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
	</LayoutTemplate>
	<ItemTemplate>
    	<asp:HyperLink ID="HyperLink1" runat="server" 
	Text='<%# Eval("Title") %>' NavigateUrl='<%# Eval("NavigationLink") %>'>
	</asp:HyperLink>
	</ItemTemplate>
</asp:ListView>
<cc1:CrumbTrailDataSource ID="CrumbTrailDataSource1" runat="server">
</cc1:CrumbTrailDataSource>
<asp:FormView ID="FormView1" runat="server" DataSourceID="NavigationDataSource1" 
	DefaultMode="Edit">
	<EditItemTemplate>
		<div><asp:Label ID="Label1" runat="server" 
			Text="Name" AssociatedControlID="TextBox1" />
		<asp:TextBox ID="TextBox1" runat="server" 
			Text="<%# Bind('[name]') %>" />
		<asp:RequiredFieldValidator ID="RequiredFieldValidator1" 
			runat="server" ControlToValidate="TextBox1" 
			EnableClientScript="False" 
			ErrorMessage="Please enter a Name" /></div>
		<div><asp:CheckBox ID="CheckBox1" runat="server" 
			Text="Over 18" Checked="<%# Bind('[over18]') %>" /></div>
		<asp:Button ID="Button1" runat="server" Text="Next" 
			CommandName="Update" />
	</EditItemTemplate>
</asp:FormView>
<cc1:NavigationDataSource ID="NavigationDataSource1" runat="server">
	<SelectParameters>
		<cc1:NavigationDataParameter Name="over18" 
			DefaultValue="false" DbType="Boolean"/>
	</SelectParameters>
</cc1:NavigationDataSource> 

The two main differences between Step2.aspx and Step1.aspx are:

  1. The StateContext Data item with key 'over18' is bound to the Checked property of the Check<code>Box. A null value is not valid, as it is a boolean, so the SelectParameters are used to initialize this to a bool of false.
  2. A ListView control is bound to a CrumbTrailDataSource to display the link back to Step1 from Step2 (see the Data Binding section of http://navigation.codeplex.com/documentation).

To the Web Site, add a Page called Summary.aspx. To this, add the ListView control bound to a CrumbTrailDataSource as included in Step2.aspx so that the user can return to Step1 or Step2 when on this Summary Page. Also add a FormView databound to a NavigationDataSource, as was done for Step1.aspx and Step2.aspx, but this time the Label Text properties are set using the 1-way databinding syntax as they are read-only (similarly there is no Update Button). The code for Summary.aspx is shown below:

ASP.NET
 <asp:ListView ID="ListView1" runat="server" 
	DataSourceID="CrumbTrailDataSource1" ItemPlaceholderID="PlaceHolder1">
	<LayoutTemplate>
		<asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
	</LayoutTemplate>
	<ItemTemplate>
    	<asp:HyperLink ID="HyperLink1" runat="server" Text='<%# Eval("Title") %>' 
		NavigateUrl='<%# Eval("NavigationLink") %>'></asp:HyperLink>
	</ItemTemplate>
</asp:ListView>
<cc1:CrumbTrailDataSource ID="CrumbTrailDataSource1" runat="server">
</cc1:CrumbTrailDataSource>
<asp:FormView ID="FormView1" runat="server" DataSourceID="NavigationDataSource1">
	<ItemTemplate>
		<div>Title: <asp:Label ID="Label1" runat="server" 
			Text='<%# Eval("[title]") %>' /></div>
		<div>Gender: <asp:Label ID="Label2" runat="server" 
			Text='<%# Eval("[gender]") %>' /></div>
		<div>Name: <asp:Label ID="Label3" runat="server" 
			Text='<%# Eval("[name]") %>' /></div>
		<div>Over 18: <asp:Label ID="Label4" runat="server" 
			Text='<%# Eval("[over18]") %>' /></div>
	</ItemTemplate>
</asp:FormView>
<cc1:NavigationDataSource ID="NavigationDataSource1" runat="server">
</cc1:NavigationDataSource> 

All that remains is to Navigate between the States/steps. To do this, add ItemUpdated listeners to the FormView controls in Step1.aspx and Step2.aspx with the code shown below:

C#
protected void FormView1_ItemUpdated(object sender, FormViewUpdatedEventArgs e)
{
	StateController.Navigate("Next");
}

Pressing F5 and filling out the details required at each step and pressing Next should Navigate through to the Summary.aspx Page, although none of the information entered is displayed! However, the crumb trail links at the top of Step2.aspx and Summary.aspx work perfectly as they Navigate to the relevant Page with the user entered data retained, i.e., the controls are prepopulated with the user's selections.

To enable the Summary.aspx Page to display the information entered requires passing the user entered data to the Summary State (see the Navigation Data section of http://navigation.codeplex.com/documentation). So the Step1 State has to pass its values to Step2 and then Step2 has to pass its values together with Step1's values to the Summary State. Cleary the more States/steps there are, the more complicated this becomes as each one has to keep track of all the data passed into it and then pass this on together with the newly entered data. However, this is where the overloaded constructor of NavigationData comes in useful as passing true to this constructor will create a NavigationData object containing all the current StateContext Data. Hence change the Navigation in the ItemUpdated listeners as shown below:

C#
protected void FormView1_ItemUpdated(object sender, FormViewUpdatedEventArgs e)
{
	StateController.Navigate("Next", new NavigationData(true));
} 

This time pressing F5 and progressing through the steps will display the Summary.aspx Page showing all the user selections.

History

  • 10th May, 2010: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --