Basic Page Design

ASP.NET pages normally are not static Web pages that display identical content each time they are opened. Certainly, portions of these pages may display fixed content hard-coded as text and XHTML much like standard Web pages. The usual situation, though, is one requiring dynamic content, displaying information that changes in response to changing user needs or to the changing status of the information itself.

Consider the page shown in Figure 2-25. When this page opens, a fixed heading and text paragraph appear, unchanging from one page display to the next. A textbox and button are displayed for user input. When the button is clicked, the page content changes. The name entered into the textbox becomes part of a dynamically created welcome message that includes the current date and time. Also, selected information is drawn from a database for display in a dynamically created table. This page setup is fairly typical for ASP.NET pages. It includes fixed and dynamic content, the latter generated by on-page scripts. It follows an input, processing, and output design model.

Welcome to My Store

Enter your name in the box below and click the button for our special offers.

Name:

Figure 2-25. Producing dynamic content for a Web page.

ASP.NET Page Coding

When creating an ASP.NET page, it is best to consider first the XHTML code and server controls needed to produce the final page display. In the above example, the results page is composed of hard-coded text and XHTML for the unchanging text portions of the page, along with five server controls to capture user input, to trigger script processing, to serve as display targets for script output, and to link to a database to retrieve information for display. These page components are coded as shown below.

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE html 
  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
  <title>Welcome Page</title>
</head>
<body>
<form Runat="Server">

<h2>Welcome to My Store</h2>

<p>Enter your name in the box below and click the button for our special 
offers.</p>

Name: <asp:TextBox id="NameIn" Runat="Server"/>
<asp:Button Text="See Specials" OnClick="Display_Output" Runat="Server"/>

<p><asp:Label id="GreetingOut" Runat="Server"/></p>

<asp:AccessDataSource id="BookSource" Runat="Server"
  DataFile="c:\eCommerce\Databases\BooksDB.mdb"
  SelectCommand="SELECT BookID, BookName, BookPrice FROM Books
                 WHERE BookSale = True
                 ORDER BY BookID"/>

<asp:GridView id="BookGrid" DataSourceID="BookSource" Runat="Server"
  Visible="False"/>

</form>
</body>
</html>
Listing 2-29. Code to produce dynamic content for a Web page.

The server controls used on this page are typical of the kinds of input, output, and script activation controls that appear on many ASP.NET pages. Although these particular controls are covered in more detail later, their general formats are summarized below so you can begin coding your own ASP.NET pages.

The <form> Tag

As mentioned previously, the <body> of an ASP.NET page includes a <form Runat="Server"> tag encompassing all page content. Its general format is repeated below.

<form Runat="Server">

  ...server controls and XHTML code

</form>
Figure 2-26. General format for <form> tag.

Pages are required to include this <form> tag any time there is a call to a subprogram from a server control. Some pages may not require it; however, it is a good idea to include this tag on all ASP.NET pages, whether required or not, just to maintain the coding habit and to ensure that any type of control can be included on the page.

The <asp:TextBox> Control

Soliciting user input to a page often makes use of a textbox for entering information. Under ASP.NET, a textbox is displayed with the <asp:TextBox> control whose basic format is shown below.

<asp:TextBox Runat="Server"
  id="id"
  Text="string"
/>
Figure 2-27. General format for <asp:TextBox> control.

As is the case with all server controls, the Runat="Server" attribute must be coded to make the TextBox accessible by server scripts. Also, an id property is required for script references to the control in order to get or set its contents and properties. The id can be any programmer-supplied identification composed of alphabetic and numeric characters along with the underscore ( _ ) character. Blank spaces cannot appear in the id value. In general, the id should be a recognizable name suggestive of the contents of the TextBox.

A TextBox normally is displayed as an empty box for user input. However, it can optionally display a text string by coding its Text property. This might be used, for instance, to initially display an example response or to display a prompt for user input. More importantly, since the Text property is a reference to the contents of the TextBox, it is the property that is referenced in scripts to process input from users who have entered data into the TextBox.

In the above example, an <asp:TextBox> control is coded in its minimal configuration to produce an empty textbox for user input. An id is supplied since a script needs to refer to this control to access the name entered into the box.

<asp:TextBox id="NameIn" Runat="Server"/>
Listing 2-30. Code for a minimally configured TextBox control.

The <asp:Label> Control

An <asp:Label> control defines an output area on the page. It is a target area where scripts place output for display. It has no visible presence except when text is assigned to the control. Its basic format is shown below.

<asp:Label Runat="Server"
  id="id"
  Text="string"
/>
Figure 2-28. General format for <asp:Label> control.

The control must include a Runat="Server" attribute for accessibility from scripts; it also must be assigned an id identification for script reference. Its Text property refers to the text characters displayed through this control. These characters can include XHTML tags in order to format or style the enclosed text.

The Label control used in the previous example contains minimal coding to identify it to a script. Since no Text property is set for the control, it has no initial value and no visible presence on the page. It serves as an output target, a "placeholder" on the page where text appears when a script assigns output to the Text property of the control.

<asp:Label id="GreetingOut" Runat="Server"/>
Listing 2-31. Code for a minimally configured Label control.

Although used here as an empty output area to await script assignment, a Label can display static text by coding its Text property. This might be done, for instance, to display an initial message on the page that is later replaced by a script-generated message.

The <asp:Button> Control

A way is needed for the user to trigger a script to write an output paragraph to the previous Label control. A typical method is to create an <asp:Button> control to call a subprogram to produce this output.

<asp:Button Runat="Server"
  id="id"
  Text="string"
  OnClick="subprogram"
/>
Figure 2-29. General format for <asp:Button> control.

An <asp:Button> control may or may not need an id. An id is not required when the button is used only to call a subprogram. If, on the other hand, the script needs to refer to the button, say to change its styling or its text label as visual confirmation that the button was clicked, then an id is required to identify this control to the script. In the present example, the script has no need to reference the button, therefore there is no need for an id.

<asp:Button Text="See Specials" OnClick="Display_Output" Runat="Server"/>
Listing 2-32. Code for a Button control.

A button's Text property provides the label displayed on the button. Of course, the label assigned should have meaning to the user, suggestive of what happens when the button is clicked.

The purpose of a Button control is to call a subprogram. This is done by coding an OnClick event handler naming the subprogram to call when the button is clicked. In this example, a subprogram named Display_Output is called.

Incidentally, if you code only the XHTML, fixed text, and form controls for an ASP.NET page, and the controls include a Button with an OnClick event handler, you will generate a compiler error when the page is opened in the browser. This error is the result of not having coded the subprogram named in the OnClick handler. If you just want to view the layout of the page prior to adding the script, be sure to remove any OnClick handlers. Then you can view the page layout. Later, after adding the script portion of the page, replace the OnClick handlers.

The <asp:GridView> Control

Along with a greeting to the user, the example page displays a list of books and prices. This list is presented as a table with three columns for the book ID, the book name, and the book price. This information is drawn directly from a database table containing this and other information. It comes from the Books table of the BooksDB.mdb database that is used in examples throughout these tutorials.

Among the many ways to display information from external data sources is the <asp:GridView> control. This control is designed especially for displaying information from a database organized into rows and columns within a table. It has a great assortment of property settings to control its layout and visual appearance; however, minimal coding can produce a default table as used in this example. The general format for a GridView in its default configuration is shown below.

<asp:GridView Runat="Server"
  id="id"
  DataSourceID="data source"
/>
Figure 2-30. General format for default <asp:GridView> control.

A GridView automatically displays as many columns as there are data fields retrieved from the database; it displays as many rows as there are records returned from the database; it produces column headings taken from the field names in the database. It presents this information in the form of an XHTML table with collapsed borders.

<asp:GridView id="BookGrid" DataSourceID="BookSource" Runat="Server"
  Visible="False" />
Listing 2-33. Code for a GridView control.

An id value is required only if the GridView is referenced from a script. In the current example this is the case, so an id is coded. In its full configuration, a GridView has numerous properties that can be set to control its display. In the current example, its Visible property is initially set to "False" so that the GridView does not appear on the page until after user input is completed.

In order for a GridView to display database information, it must be associated with a data source control. This control connects to the database and retrieves a set of records for display. The data source control is bound to the GridView through the GridView's DataSourceID property. In the current example, the property setting DataSourceID="BookSource" points to this named data source control as the source of the GridView's displayed information.

The <asp:AccessDataSource> Control

The data source control used to interface with Microsoft Access databases is the <asp:AccessDataSource> control. Its general format to retrieive a set of records from a database table is shown below.

<asp:AccessDataSource Runat="Server"
  id="id"
  DataFile="database path"
  SelectCommand="SQL SELECT statement"
/>
Figure 2-31. General format for <asp:AccessDataSource> control.

The id assigned to the control must match that given in the DataSourceID property of the display control for which this is the data source. The DataFile property gives the server path to the database; the SelectCommand property is an SQL SELECT statement to retrieve a set of records from the database. This is all the information needed to produce a recordset that can be bound to a GridView or to other output controls for display of database information.

<asp:AccessDataSource id="BookSource" Runat="Server"
  DataFile="c:\eCommerce\Databases\BooksDB.mdb"
  SelectCommand="SELECT BookID, BookName, BookPrice FROM Books
                 WHERE BookSale = True
                 ORDER BY BookID"/>
Listing 2-34. Code for an AccessDataSource control.

In the current example, an AccessDataSource links to the BooksDB.mdb database. This database is located on the server's c: drive in the Databases subdirectory of the eCommerce directory. An SQL SELECT statement retrieves three fields of information from all records in the Books table where a book is on sale; the records are returned in sorted order by the BookID field. In this example, seven records are extracted from the table and made available through this control.

Binding a Data Source to a Control

When a page is first opened, the AccessDataSource immediately issues its SelectCommand to retrieve the specified records from the database. This recordset is then available for binding to any display control that identifies this data source in its DataSourceID property. Binding involves displaying the data values contained in the data source through a display control coded on the page. In this case, it is the GridView that binds to the data source, formatting the returned recordset as a displayed table.

Although the example GridView is fully loaded and formatted for display when the page opens, it should not be displayed until after the user enters a name and clicks the button. So, the GridView's Visible property is initially set to "False" to keep it hidden from view. It is revealed programmatically in the subprogram that is called to display the welcome message.

At this point, all of the XHTML, fixed text, and server controls have been coded for the page. All that remains is to code the script to make it all work.

ASP.NET Script Coding

The script portion of a page is coded at the top of the page, prefixed by any needed page directives and enclosed inside <script> tags. This general outline is fleshed out for the example page as shown in Listing 2-35. You might be surprised to see that very little scripting is needed to animate the application. This is because much of the work is behind the scenes, encapsulated inside server controls to save you from having to code processing details. There is only one subprogram containing three Visual Basic statements needed to perform all processing.

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE html 
  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<%@ Page Language="vb" Debug="True" %>

<SCRIPT Runat="Server">

Sub Display_Output (Src As Object, Args As EventArgs)

  If NameIn.Text <> "" Then
    
    GreetingOut.Text = "Hello, <b>" & NameIn.Text & "</b>." _
      & " Today is " & Format(DateString, "Long Date") _
      & " and the time is " & Format(TimeString, "Long Time") & "." _
      & " Check out our special prices on computer books listed" _
      & " below:<br/>"
    
    BookGrid.Visible = True
    
  End If

End Sub

</SCRIPT>

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
  <title>Welcome Page</title>
</head>
<body>
<form Runat="Server">

<h2>Welcome to My Store</h2>

<p>Enter your name in the box below and click the button for our special 
offers.</p>

Name: <asp:TextBox id="NameIn" Runat="Server"/>
<asp:Button Text="See Specials" On_Click="Display_Output" Runat="Server"/>

<p><asp:Label id="GreetingOut" Runat="Server"/></p>

<asp:AccessDataSource id="BookSource" Runat="Server"
  DataFile="c:\eCommerce\Databases\BooksDB.mdb"
  SelectCommand="SELECT BookID, BookName, BookPrice FROM Books
                 WHERE BookSale = True
                 ORDER BY BookID"/>

<asp:GridView id="BookGrid" DataSourceID="BookSource" Runat="Server"
  Visible="False"/>

</form>
</body>
</html>

Listing 2-35. Script to produce dynamic content for a Web page.

A page directive is included at the top of the page giving the optional Language specification and permitting Debug error messages to appear at the developer's PC.

The Display_Output subprogram, being called by a button click, has the necessary signature for a button-activated subprogram. Although no script reference is made to the source (Src) object making the call or to any arguments (Args) being passed, this signature still must be supplied for any button-activated subprogram.

Script processing accomplishes two things. First, it produces the text welcome message integrating the user's name from the TextBox; then it reveals the GridView table. Both of these actions are contingent on the user entering a name; therefore, the script is enclosed inside a Visual Basic If...End If decision structure to run only if a name is available in the TextBox.

Sub Display_Output (Src As Object, Args As EventArgs)

  If NameIn.Text <> "" Then
    
    ...rest of script
  
  End If

End Sub
Listing 2-36. Testing for available input data.

Script references to properties of server controls follow common dotted notation practices; that is, the id of the control is followed by a property name, separated by a period.

ControlId.property
Figure 2-32. General format for script references to control properties.

The script reference NameIn.Text refers to the value (Text property) entered into the TextBox control (id="NameIn") as user input. The If statement tests this NameIn.Text property to ensure that it is not empty, or null (NameIn.Text <> ""). With a name available, the script proceeds to formulate the welcome message. This is a matter of producing a text string for assignment to the Text property of the GreetingOut Label control.

This output string is a concatenation of fixed text, the name from the TextBox, and a couple of Visual Basic date and time properties formatted for display. The text string also includes XHTML tags to assist in its formatting. The five lines of code are continuations of a single assignment statement.

    GreetingOut.Text = "Hello, <b>" & NameIn.Text & "</b>." _
      & " Today is " & Format(DateString, "Long Date") _
      & " and the time is " & Format(TimeString, "Long Time") & "." _
      & " Check out our special prices on computer books listed" _
      & " below:<br/>"
Listing 2-37. Concatenating a string for output display.

Finally, the script reveals the GridView table (id="BookGrid") by settings its Visible property to True.

    BookGrid.Visible = True
Listing 2-38. Revealing a hidden server control

The above example is a demonstration of the coding of and relationships between server controls and script elements. It presents some common controls and their minimal coding, along with typical ways in which scripts interact with these controls. It is not meant as full coverage of the controls nor as definitive methods of coding subprograms. The example should, however, give you a sense of the general approach to coding ASP.NET pages.

Scripting the Page_Load Event

The previous example is a common scenario where a user action causes a subprogram to run. It is often the case, however, that scripts do not require user actions to invoke. They can be run in response to events produced by the page itself. As mentioned previously, a common trigger for scripts is the page's load event, when the page is accessed from server storage and loaded into server memory prior to its transmittal to the requesting browser. The following page produces the current date and time automatically each time the page loads, that is, when the page is initially loaded by the server when the page first opens (the load event) and when the page is reloaded by a button click (a post-back event). Full coding for this application is shown below.

Welcome to My Page

Today is Sunday, February 05, 2012.
The time is 8:54:37 AM.

Figure 2-33. Producing dynamic content during page loading.
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE html 
  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<%@ Page Language="vb" Debug="True" %>

<SCRIPT Runat="Server">

Sub Page_Load
  DateOut.Text = Format(DateString, "Long Date")
  TimeOut.Text = Format(TimeString, "Long Time")
End Sub

</SCRIPT>

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
  <title>Welcome Page</title>
</head>
<body>
<form Runat="Server">

<h2>Welcome to My Page</h2>

Today is <asp:Label id="DateOut" Runat="Server"/>.<br/>
The time is <asp:Label id="TimeOut" Runat="Server"/>.<br/>
<br/>
<asp:Button Text="Update Time" Runat="Server"/>

</form>
</body>
</html>
Listing 2-39. Code to produce dynamic content during page loading.

Two <asp:Label> controls are defined to receive script output. These controls are surrounded by fixed text that does not change on loading and reloading of the page. A button is provided to update the date and time. Notice that the button does not include an OnClick event handler. It does not call a specific subprogram; it merely causes the page to be reloaded.

Since the script should run each time the page loads, it is placed inside the special Page_Load subprogram, so-named for this purpose. The subprogram does not require an argument list since it is not explicitly called by an event handler. The subprogram is run each time the page is opened to assign system date and time information to the Label controls. It runs, then, the first time this page is accessed and each time the button is clicked to reload the page.

Handling Post-Back Events

As noted, there are two distinct kinds of events that cause the Page_Load subprogram to run. One event is an initial page load event, occuring the first time a page is accessed, normally in response to a URL request for the page. The other event is a page post-back event, a reloading of the page in response to a user event such as a mouse click. It is sometimes important to differentiate between these two events in coding the Page_Load subprogram.

Consider the following application. When this page is first loaded into server memory in response to a URL request, the page is time-stamped in the Page_Load subprogram with the date and time it was first accessed. It currently reports when you first opened this page. This date and time should not change, though, even when the button click causes a post-back event to reload the page and rerun the Page_Load subprogram. The date and time should remain as initially reported even though time moves forward.

Welcome to My Page

You first arrived at this page on Sunday, February 05, 2012 at 8:54:37 AM.

Figure 2-34. Maintaining content on page post-back.

In clicking the above button you will notice that the date and time do not change, even though their reporting appears in the Page_Load subprogram which is run each time the button is clicked. The reason the date and time are not updated is because the script differentiates between the first time the page is loaded and subsequent times the page is loaded.

This Page_Load subprogram avoids updating the date and time by testing for a post-back event. This is done by testing the page's IsPostBack property.

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE html 
  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<%@ Page Language="vb" Debug="True" %>

<SCRIPT Runat="Server">

Sub Page_Load

  If Not Page.IsPostBack Then
    DateOut.Text = Format(DateString, "Long Date")
    TimeOut.Text = Format(TimeString, "Long Time")
  End If

End Sub

</SCRIPT>

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
  <title>Welcome Page</title>
</head>
<body>
<form Runat="Server">

<h2>Welcome to My Page</h2>

You first arrived at this page on 
<b><asp:Label id="DateOut" Runat="Server"/></b> at
<b><asp:Label id="TimeOut" Runat="Server"/></b>.

<p><asp:Button Text="Post Back" Runat="Server"/></p>

</form>
</body>
</html>
Listing 2-40. Code to maintain dynamic content on page post-back.

The Page.IsPostBack condition is True when the page is reloaded due to a post-back event such as a button click to reload the page or to call a subprogram. Therefore, the condition "Not Page.IsPostBack" identifies the situation where the page is not posted back. The script is run, then, only when the page is initially loaded. When the button click posts back the page, the script is not run. You will notice, though, that if you reload this page from the tutorial menu or if you refresh the page with the browser's Refresh button, a new date and time are reported. In these cases the page is loaded anew, not posted back through a server control. As in the previous example, the button click does not call a named subprogram; it just posts back the page to cause the Page_Load subprogram to run.

The above examples are typical of the kinds of processing performed by ASP.NET pages. Although these are relatively simple examples, they illustrate the common layout and coding of pages and the sorts of processing requests they handle. Regardless of how complex page processing may appear, it normally involves some combination of input controls, script activation controls, output controls, data source controls, and information display controls arranged and activated in a similar manner to those described above.