You want to create a form that appears, from
the
user’s prospective, to consist of multiple pages,
while keeping all of your code in one .aspx
file
and the code-behind that accompanies it.
Create one ASP.NET page. Use panels to separate the HTML for each of
the “virtual” pages you wish to
display, and simulate a multipage form by enabling one panel at a
time. The output of a typical three-page form is shown in Figures
Figure 3-1 through Figure 3-3.
Example 3-13 through Example 3-15 show the .aspx
and
code-behind files for an application that implements this solution.
In classic ASP, a series of questions or prompts, such as those on a
survey or wizard, are typically implemented using multiple ASP pages
with each submitting to the next in turn. ASP.NET allows you to
submit a form to itself, which means that you have to rethink how to
implement a survey, wizard, or traditionally multipart form. The
solution we advocate involves defining multiple panels on a single
form with the ASP:Panel
control, and showing or
hiding the panels as required. For example, the application
we’ve written uses this technique to display a
series of questions in a short survey.
Refer to Recipe 3.3 if you are determined to stick to the multiple form approach.
In our example, the .aspx
file contains three
panels and a Next button. The first panel contains the first question
(“Do you currently use ASP.NET?”)
with two radio buttons for the response. The second panel contains
the second question (“How long have you been using
ASP.NET?”) with a drop-down list for the response.
The third panel contains a message thanking the user for taking the
survey. A Next button is used to move from one panel to the next.
The code-behind contains a reference to each of the panels to provide
you with the ability to show and then hide any particular panel as
the survey progresses. For this example, an object,
Survey
, is used to save the current question
number and the response to each question asked. The
Survey
object is marked as
Serializable
to allow the objects of this type to
be stored in the viewstate
. The class is defined
as follows:
<System.Serializable
( )> Private Class Survey Public currentQuestion As Integer Public response1 As Boolean Public response2 As Integer End Class[System.Serializable( )]
private class Survey { public int currentQuestion; public Boolean response1; public int response2; }
A constant, VS_SURVEY_DATA
, is used to define the
name of the variable placed in the viewstate
. This
improves maintainability of the code, because the variable in the
viewstate
is accessed from several locations in
the code.
In the Page_Load
method, the
Survey
object is initialized and stored in the
viewstate
. The form is then set up to initially
display the first question in the series.
When the Next button is clicked, the form is posted back to itself
and the btnNext_Click
method is executed. The
first action performed is to rehydrate the
Survey
object from the
viewstate
. Next, the current question is checked
to see what response should be stored and which panel should next be
made visible:
If the first question was just answered, its response is stored in
the Survey
object, the question number is
incremented, the Survey
object is again stored in
the viewstate
, and the second question is made
visible.
If the second question was just answered, its response is stored in
the Survey
object (more permanent storage would be
used instead if this were a real application), and the thank-you
panel is made visible.
This example could be extended in many ways. One enhancement would be
to create a totally data-driven survey form. In the
.aspx
file, a panel would be needed for each
type of response (free-form, yes/no, selection, etc.). In the
code-behind, an XML document, database, or some other data store
could be used and a collection of data defined that contains the
questions, type of response, etc. Based on this data, the appropriate
panel would be displayed for each question.
Another possible enhancement is that instead of collecting all of the
responses and storing them in the viewstate
until
the survey is completed, the responses could be stored in a database
or other data store as the survey proceeds. This would be a better
approach if the survey is long or storing partial data is desirable.
Recipe 3.3 for a multiple form approach
Example 3-13. Simulating a multipage form (.aspx)
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="Ch03MultiPageVB.aspx.vb" Inherits="ASPNetCookbook.VBExamples.CH03MultiPageVB" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>FormMultiPageVB</title> <link rel="stylesheet" href="css/ASPNetCookbook.css"> </head> <body leftmargin="0" marginheight="0" marginwidth="0" topmargin="0"> <form id="frmMultiPage" method="post" runat="server"> <table width="100%" cellpadding="0" cellspacing="0" border="0"> <tr> <td align="center"> <img src="images/ASPNETCookbookHeading_blue.gif"> </td> </tr> <tr> <td class="dividerLine"> <img src="images/spacer.gif" height="6" border="0"></td> </tr> </table> <table width="90%" align="center" border="0"> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <tr> <td align="center" class="PageHeading"> MultiPage Form (VB) </td> </tr> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <tr> <td align="center"><asp:Panel ID="pnlQuestion1" Runat="server">
<table width="60%" border="0">
<tr>
<td class="MenuItem">Do you currently use ASP.NET?</td>
<td>
<asp:RadioButtonList ID="radQuestion1" Runat="server"
RepeatDirection="Horizontal"
CssClass="MenuItem" >
<asp:ListItem Value="1">
Yes
</asp:ListItem>
<asp:ListItem Value="0" Selected="True">
No
</asp:ListItem>
</asp:RadioButtonList>
</td>
</tr>
</table>
</asp:Panel>
<asp:Panel ID="pnlQuestion2" Runat="server">
<table width="80%" border="0">
<tr>
<td class="MenuItem">How long have you been using ASP.NET?</td>
<td class="MenuItem">
<select id="selQuestion2" runat="server">
<option value="0">-- Select One --</option>
<option value="1">0-6 Months</option>
<option value="2">7-12 Months</option>
<option value="3">13-24 Months</option>
<option value="4">24+ Months</option>
</select>
</td>
</tr>
</table>
</asp:Panel>
<asp:Panel ID="pnlThankyou" Runat="server">
<table width="60%" border="0">
<tr>
<td class="MenuItem" align="center">
Thank you for taking our survey
</td>
</tr>
</table>
</asp:Panel>
<br /><asp:ImageButton ID="btnNext" Runat="server"
ImageUrl="images/buttons/button_nextQuestion.gif" />
</td> </tr> </table> </form> </body> </html>
Example 3-14. Simulating a multipage form code-behind (.vb)
Option Explicit On Option Strict On '----------------------------------------------------------------------------- ' ' Module Name: CH03MultiPageVB.aspx.vb ' ' Description: This module provides the code behind for ' CH03MultiPageVB.aspx ' '***************************************************************************** Namespace ASPNetCookbook.VBExamples Public Class CH03MultiPageVB Inherits System.Web.UI.Page 'panels on the form Protected pnlQuestion1 As System.Web.UI.WebControls.Panel Protected pnlQuestion2 As System.Web.UI.WebControls.Panel Protected pnlThankyou As System.Web.UI.WebControls.Panel 'control for response to question 1 Protected radQuestion1 As System.Web.UI.WebControls.RadioButtonList 'control for response to question 2 Protected selQuestion2 As System.Web.UI.HtmlControls.HtmlSelect 'buttons to navigate through survey Protected WithEvents btnNext As System.Web.UI.WebControls.ImageButton'the following class defines the container to store the survey data
<System.Serializable( )> Private Class Survey
Public currentQuestion As Integer
Public response1 As Boolean
Public response2 As Integer
End Class
'the following constant defines the variable used to store the survey
'data in the viewstate
Private VS_SURVEY_DATA As String = "SurveyData"
'************************************************************************* ' ' ROUTINE: Page_Load ' ' DESCRIPTION: This routine provides the event handler for the page load ' event. It is responsible for initializing the controls ' on the page. '------------------------------------------------------------------------- Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Dim surveyData As SurveyIf (Not Page.IsPostBack) Then
'initialize survey data
surveyData = New Survey
surveyData.currentQuestion = 1
surveyData.response1 = False
surveyData.response2 = -1
'store the survey in the viewstate to use on the
'next submittal
viewstate.Add(VS_SURVEY_DATA, surveyData)
'make the first question visible
pnlQuestion1.Visible = True
pnlQuestion2.Visible = False
pnlThankyou.Visible = False
End If
End Sub 'Page_Load '************************************************************************* ' ' ROUTINE: btnNext_Click ' ' DESCRIPTION: This routine provides the event handler for the next ' button click event. '-------------------------------------------------------------------------Private Sub btnNext_Click(ByVal sender As Object, _
ByVal e As System.Web.UI.ImageClickEventArgs) _
Handles btnNext.Click
Dim surveyData As Survey
'get the object from the viewstate with the survey data
surveyData = CType(viewstate.Item(VS_SURVEY_DATA), Survey)
Select Case surveyData.currentQuestion
Case 1
'store answer to first question
If (radQuestion1.SelectedItem.Value = "0") Then
surveyData.response1 = False
Else
surveyData.response1 = True
End If
'increment the question number
surveyData.currentQuestion += 1
'store the survey in the viewstate to use on the
'next submittal
viewstate.Add(VS_SURVEY_DATA, surveyData)
'make 2nd question visible
pnlQuestion1.Visible = False
pnlQuestion2.Visible = True
Case 2
'store answer to second question
surveyData.response2 = CInt(selQuestion2.Value)
'the survey is complete so store the answers per your
'applications required (database, etc.)
'make thank you panel visible
pnlQuestion2.Visible = False
pnlThankyou.Visible = True
btnNext.Visible = False
Case Else
'error case
End Select
End Sub 'btnNext_Click
End Class 'CH03MultiPageVB End Namespace
Example 3-15. Simulating a multipage form code-behind (.cs)
//---------------------------------------------------------------------------- // // Module Name: CH03MultiPageCS.aspx.cs // // Description: This module provides the code behind for // CH03MultiPageCS.aspx // //**************************************************************************** using System; using System.Web.UI; namespace ASPNetCookbook.CSExamples { public class CH03MultiPageCS : System.Web.UI.Page { // panels on the form protected System.Web.UI.WebControls.Panel pnlQuestion1; protected System.Web.UI.WebControls.Panel pnlQuestion2; protected System.Web.UI.WebControls.Panel pnlThankyou; // control for response to question 1 protected System.Web.UI.WebControls.RadioButtonList radQuestion1; // control for response to question 2 protected System.Web.UI.HtmlControls.HtmlSelect selQuestion2; // buttons to navigate through survey protected System.Web.UI.WebControls.ImageButton btnNext;// the following class defines the container to store the survey data
[System.Serializable( )]
private class Survey
{
public int currentQuestion;
public Boolean response1;
public int response2;
}
// the following constant defines the variable used to store the survey
// data in the viewstate
private const String VS_SURVEY_DATA = "SurveyData";
//************************************************************************ // // ROUTINE: Page_Load // // DESCRIPTION: This routine provides the event handler for the page // load event. It is responsible for initializing the // controls on the page. //------------------------------------------------------------------------ private void Page_Load(object sender, System.EventArgs e) { Survey surveyData = null; // wire the next button click event this.btnNext.Click += new ImageClickEventHandler(this.btnNext_Click);if (!Page.IsPostBack)
{
// initialize survey data
surveyData = new Survey( );
surveyData.currentQuestion = 1;
surveyData.response1 = false;
surveyData.response2 = -1;
// store the survey in the viewstate to use on the
// next submittal
ViewState.Add(VS_SURVEY_DATA, surveyData);
/// make the first question visible
pnlQuestion1.Visible = true;
pnlQuestion2.Visible = false;
pnlThankyou.Visible = false;
}
} // Page_Load //************************************************************************ // // ROUTINE: btnNext_Click // // DESCRIPTION: This routine provides the event handler for the next // button click event. //------------------------------------------------------------------------private void btnNext_Click(Object sender,
System.Web.UI.ImageClickEventArgs e)
{
Survey surveyData = null;
// get the object from the viewstate with the survey data
surveyData = (Survey)(ViewState[VS_SURVEY_DATA]);
switch (surveyData.currentQuestion)
{
case 1:
// store answer to first question
if (radQuestion1.SelectedItem.Value == "0")
{
surveyData.response1 = false;
}
else
{
surveyData.response1 = true;
}
// increment the question number
surveyData.currentQuestion ++;
// store the survey in the viewstate to use on the
// next submittal
ViewState.Add(VS_SURVEY_DATA, surveyData);
// make 2nd question visible
pnlQuestion1.Visible = false;
pnlQuestion2.Visible = true;
break;
case 2:
// store answer to second question
surveyData.response2 = System.Convert.ToInt32(selQuestion2.Value);
// the survey is complete so store the answers per your
// applications required (database, etc.)
// make thank you panel visible
pnlQuestion2.Visible = false;
pnlThankyou.Visible = true;
btnNext.Visible = false;
break;
default:
// error case
break;
} // switch (surveyData.currentQuestion)
} // btnNext_Click
} // CH03MultiPageCS }