MSDN Magazine > Issues and Downloads > 2001 > May >  ASP.NET: Web Forms Let You Drag And Drop Your W...

ASP.NET: Web Forms Let You Drag and Drop Your Way to Powerful Web Apps

Jeff Prosise
This article assumes you�re familiar with ASP, Visual Basic or C#
Level of Difficulty     1   2   3 
Download the code for this article: WebForms.exe (41KB)
Browse the code for this article at Code Center: WebFormsSample
SUMMARY Web Forms have the potential to change Web programming by introducing a new programming model built around server-side controlsâ€"a model in which controls render their own UIs by generating HTML to return to clients and firing events that are handled by server-side scripts. Since all the action takes place on the Web server, virtually any browser can run a Web Forms app. And thanks to Visual Studio.NET, building a Web Forms app is a lot like using Visual Basic: just drop a control onto a form then write an event handler. This article describes the Web Forms programming model, how it fits with ASP.NET, and introduces DataGrid, TextBox, and other classes in the .NET Framework class library.
Any developer who has written Web applications knows that Web development is no picnic. Whereas the programming model for traditional applications is well-established and supported by a plethora of languages, tools, and development environments, Web programming is a hodgepodge of markup languages, scripting environments, and server platforms. And unfortunately for the average programmer, the knowledge and skills required to write a Web application have little in common with those needed to do traditional application development.
      Help is on the way, and it's riding into town on a horse named Web Forms. Web Forms are part of ASP.NET, which is part of Microsoft® .NET, the revolutionary computing platform that promises to change softwareâ€"particularly Web softwareâ€"as you know it. Web Forms offer a compelling new way to architect Web software. They bridge the gap between traditional application models and Web programming models by making use of the same form-based programming paradigm that's already familiar to legions of Windows®-based developers. In Visual Studio.NET, the forthcoming release of Visual Studio® that's aimed squarely at .NET, Web applications are created by dropping controls onto forms, then double-clicking those controls and writing event handlers. A lot of magic goes on behind the scenes to enable this to work, but most of it's transparent to the developer who simply wants to get a Web application up and running with as little friction as possible.
      Web Forms are combinations of HTML, code, and prepackaged server components (controls) that execute on a Web server running Microsoft Internet Information Services (IIS) and they display a user interface by generatingâ€"for the most partâ€"ordinary HTML to return to browsers. The code can be written in Visual Basic®, C#, or any other language that's supported by a .NET compiler, and what's more, it's compiled code so it offers the swiftest possible execution. The controls come from the .NET Framework class library, which provides the API common to all .NET-based executables. Some controls are little more than wrappers around simple HTML tags, but others represent complex UI objects that generate hundreds of lines of HTML, and in cases when the browser supports it, client-side script. Moreover, Web Forms code and data are easily segregated into separate files, enabling developers to avoid the spaghetti-like concoctions of HTML and script that characterize many of today's Active Server Pages (ASP) applications.
      This article introduces the Web Forms programming modelâ€"what it is, how it's used, and what makes it workâ€"with a special emphasis on how Web Forms are structured and on the many control types that the .NET Framework class library places at your disposal. I generated all the sample code by hand (that is, without Visual Studio.NET) because I wanted it to be as straightforward and uncluttered as possible, and because I didn't want important architectural details to be hidden behind wizard-generated code. However, all the samples presented in this article can easily be duplicated using the rich layout and development environment of Visual Studio.NET.
      To run the samples, you'll need to install the .NET Framework SDK Beta 1, which you can download from the .NET Developer Center at http://msdn.microsoft.com/library/default.asp?url=/nhp/Default.asp?contentid=28000519. While you're there, take time to order Visual Studio.NET Beta 1 on CD. Keep in mind that because .NET is an evolving product and many details are not cast in stone, anything you read in this article is subject to change before final release. (How's that for hedging my bets?)

Your First Web Form

      The best way to learn a new programming paradigm is to write code that exercises it. Therefore, I'll begin this journey through Web Forms by writing a simple Web Forms applicationâ€"a mortgage calculator that takes a principal amount, interest rate, and loan length (in months) and computes a monthly payment.
      Many texts that introduce Web Forms assume that you already know ASP. I'm not going to make that assumption. I'm going to begin with a simple HTML form that provides a user interface for a mortgage calculator and transform it, step-by-step, into a full-blown Web Forms application. If you're an ASP guru, feel free to skip ahead to the Web Forms code in Figure 7. But if you're new to Web programming, the following discussion might be helpful.
      The code in Figure 1 is the HTML for a simple mortgage calculator form. It is basic HTML that can be displayed by any modern browser (see Figure 2).

Figure 2 HTML Mortgage Calculator
Figure 2 HTML Mortgage Calculator

The form itself is delimited by <form> tags. It contains a three-row, two-column table which is used to visually align the form's elements. The elements are three labels composed of raw HTML text, three text fields to capture user input, and a button labeled Calculate. When the user clicks the button, the browser extracts the user's input from the text fields, appends them to the URL, and navigates to the resulting URL. For example, if the user enters 100000 in the Principal field, 0.10 (for 10 percent) in the Interest Rate field, and 240 in the Months field, the generated URL is:
http://.../mcalc.html?Principal=100000&Rate=0.10&Months=240
      The only problem is that there's nothing on the other end to extract the input parameters from the URL and do something with them. In other words, this HTML form is nothing more than a pretty face.
      One way to turn this simple form into a Web application is to embed in it a client-side script that processes the user's input and performs mortgage calculations locally (that is, in the browser). Of course, client-side scripting has its pitfalls, not the least of which is that some older and less popular browsers don't support it. The alternative is to do the processing on the server, where an application can perform the computation and return ordinary HTML that's compatible with any browser.
      One way to do this is to process the input with a CGI script or an ISAPI DLL. IIS users have another option: an ASP application. An ASP page is a Web page that contains a mix of HTML and script. The script, which is typically written in VBScript or JScript®, executes on the server and generates HTML to return to the client. ASP scripts can do just about anything you want, from writing simple HTML to the output stream to performing SQL queries on back-end databases.
      A very simple ASP page looks like this:
<%@ Language="VBScript" %>
<html>
  <head>
    <title>Simple ASP Page</title>
  </head>
  <body>
    <h1>Today's date is <%= Date %></h1><p>
    <h1>The current time is <%= Time %></h1>
  </body>
</html>
The Language directive tells the Web server that code in the <% %> blocks is written in VBScript. Date and Time are VBScript functions that return text strings reflecting the current date and time, and the <%= symbols insert those strings into the HTML output stream. The HTML returned to the client is generic to any browser and looks like this:
<html>
  <head>
    <title>Simple ASP Page</title>
  </head>
  <body>
    <h1>Today's date is 11/17/2000</h1><p>
    <h1>The current time is 4:00:15 PM</h1>
  </body>
</html>
      ASP pages are a wonderful mechanism for dynamically generating content when static HTML just isn't good enough. And ASP requires no special support on the client side because all the work is done on the server.
      I can use ASP to turn my mortgage calculator into a real Web application (see Figure 3). Note the attributes that are added to the <form> tag. The method="post" attribute instructs the browser to encode the input parameters in the body of the request that it sends to the server (as opposed to encoding them in the URL). The action="MCalc.asp" attribute identifies the ASP page that's to be activated when the Calculate button is clicked.
      Because the file in Figure 3 is named MCalc.asp, clicking the button submits the form back to itself. This is called a postback. When a postback occurs, the input parameters accompanying the request are exposed to ASP scripts via the ASP Request object. The script in Figure 3 extracts the user's input from the Request object, computes a monthly payment, and then uses the ASP Response object to write HTML-formatted results to the output stream. The result is shown in Figure 4. The Monthly Payment line at the bottom of the window is generated when the script calls the Response object's Write method. That line doesn't appear before the Calculate button is clicked because the script won't execute the call to Response. Write if the input parameters are null.

Figure 4 ASP Mortgage Calculator
Figure 4 ASP Mortgage Calculator

      So far, so good. But if you run the ASP page in Figure 3, you'll find that it suffers from one rather severe deficiency: when the postback occurs and a new page is returned to the client, the values entered in the text fields disappear. That's because the HTML returned from the Web server represents a brand new HTML page and ASP does nothing to help controls maintain state across postbacks. To fix that, you'll need more code.
      The modified version of the MCalc form (see Figure 5) incorporates the input values in the HTML returned to the client so the text fields don't blank out when the user clicks the Calculate button. The key is the scripted Value attributes added to the <input> tags. When the form is initially displayed, Request("Principal"), Request("Rate"), and Request("Months") return null strings that result in empty Value fields:
<input type="text" name="Principal" value="">
<input type="text" name="Rate" value="">
<input type="text" name="Months" value="">
But after the postback, the same expressions evaluate to the strings that the user entered, yielding the following HTML:
<input type="text" name="Principal" value="100000">
<input type="text" name="Rate" value="0.10">
<input type="text" name="Months" value="240">
      Figure 6 shows the result. Now both the input and output values are visible after the Calculate button is clicked, reinforcing the illusion that the user is seeing just one page when, in fact, she is seeing two.

Figure 6 Text Fields Retain Text
Figure 6 Text Fields Retain Text

      So what can you do to improve the model in Figure 5? Not much if you stick to ASP. But there's a lot you can do if you switch to ASP.NETâ€"specifically, the part of ASP.NET known as Web Forms. Figure 7 and Figure 8 show the Web Forms version of my mortgage calculator. Several important differences distinguish the two versions.

Figure 8 Web Forms Version (mcalc.aspx)
Figure 8 Web Forms Version (mcalc.aspx)

      The first and most noticeable difference is that the HTML <input> tags have been replaced with Web Forms controlsâ€"specifically, with TextBox controls representing text input fields and a Button control representing the Calculate button. The RunAt="server" attributes tell the Web server that the controls are to be handled on the server side (which means that they will be rendered back to the client as HTML) and that server-side scripts can reference them using their control IDs (for example, ID="Principal"). Controls such as these, known as server controls, form the foundation of Web Forms applications. TextBox and Button are but two of many server control classes featured in the .NET Framework class library. You'll learn much more about server controls later in this article.
      The second difference is the script that performs mortgage calculations. It's written in C#, not VBScript, and it's linked to the Calculate button by the OnClick attribute in the Button tag. Moreover, it doesn't use the ASP Request object to gather user input. Instead, it reads strings directly from the form's TextBox controls using statements such as this one:
string strPrincipal = Principal.Text;
Principal is the ID assigned to the Principal field in the <asp:TextBox> tag; Text is a property that exposes the text contained in a TextBox control.
      A third difference is how the Web Forms mortgage calculator reports the computed monthly payment to the client. Rather than write out HTML using the ASP Response object, OnCalculate assigns text directly to the Label control (<asp:Label>) named Output, like so:
Output.Text = "Monthly Payment = " + strResult;
      A fourth and final difference between the ASP and ASP.NET versions of the application is that the ASP.NET <form> tag has neither a Method nor an Action attribute. These attributes are no longer necessary because the form is now marked runat="server". If you examine the HTML returned by MCalc.aspx, you'll see that Method and Action attributes are added to the <form> tag automatically.
      Notice in Figure 7 the total absence of any code to maintain state in the text fields across postbacks. Such code is no longer necessary because Web Forms automatically persist control state across postbacks. Check the HTML returned after the postback and you'll see that the <input> tags generated from the TextBox controls have Value attributes attached to them that restore the text the user typed into the form.
      This example demonstrates the most important tenets of the Web Forms programming model:
  • Controls handle the heavy lifting involved in rendering an application's UI.
  • Controls fire events and handlers respond to those events. Code packaged with a page can interact with the page's controls.
  • Controls retain their state across postbacks.
      In effect, postbacks have been abstracted away, creating a virtual world where everything appears to happen within a single, unified codespace. It's an illusion, but an effective one. And it has all kinds of benefits, not the least of which is that because the bulk of the work is done on the server, virtually any browser in existence can run a Web Forms application. Prepackaged server controls are a huge plus, too, because they reduce complex UI elements to simple HTML-like tags, and promoting smart server components that adapt their output to the target browser.
      Of course, this example barely scratches the surface, but it helps you see the big picture. Now that you have the landscape well in focus, let's zoom in on the details and see what else Web Forms can do to help you write cutting-edge Web applications.

ASP.NET Applications

      If you want to learn the Web Forms programming model, it helps to understand exactly what comprises an ASP.NET application. An application is defined as the set of files in an IIS virtual directory and its subdirectories. In Windows 2000, you create virtual directories using the Computer Management applet found in Administrative Tools. (If you create a Web Application project with Visual Studio.NET, it automatically creates a new virtual directory for you.) The files that constitute an ASP.NET application typically include:
  • A Global.asax file containing application-level program directives, handlers for application and session-level events, and declarations of objects that are globally accessible to all parts of the application.
  • A Config.web file containing configuration information.
  • One or more ASPX files containing Web Forms.
  • One or more code filesâ€"written in C#, Visual Basic, and so onâ€"containing the application's code.
      Code files aren't always present in the virtual directory because code can optionally be placed in the ASPX files (as it was in MCalc.aspx). But most Web Forms applicationsâ€"especially those created with Visual Studio.NETâ€"segregate code and data into separate files. I'll say more about how that's accomplished shortly.
      I'll leave a full discussion of Global.asax and Config.web for another time. But briefly, Global.asax is to ASP.NET what Global.asa is to ASP. If you want to trap events such as Application_Start, Application_End, Session_Start, and Session_End (which are fired when applications start and stop and sessions begin and end) you put the event handlers in Global.asax. Typical uses for these event handlers include initializing state for each user (such as shopping carts) and manipulating program counters. Config.web is new to ASP.NET. It's an XML-formatted file that stores an application's configuration settings. It's a welcome improvement over ASP, whose insistence on storing configuration data in the IIS metabase makes moving an application from one machine to another a chore. Plus, because it's a text file, Config.web can be edited with a text editor like Notepad.

Application Pages

      Each ASPX file included in a Web Forms application constitutes one page of the application. The first time a page is requested, ASP.NET dynamically generates a class to represent that page by deriving from System.Web.UI.Page. After compiling the derived class and caching the compiled executable in a special directory (so subsequent requests for the same page will execute much faster), ASP.NET instantiates the class and executes it to generate HTML to return to the client.
      The HTML included in the output stream comes from the HTML present in the ASPX file, the page's controls, and any scripts that write out HTML of their own. After it's executed, the instance of the page object is discarded. Thus, a page object's lifetime lasts from the time it's instantiated following each new request, until the request is complete.
      During its lifetime, a page undergoes several distinct phases. As it enters each new phase, the page fires an event that can be processed with a server-side script. For Web Forms developers, the most important page-level event is Page_Load, which is called each time the page is instantiated. Because Page_Load is called before the page is rendered to the client, it's a great place to perform any one-time initializations that need to happen before rendering takes place. Developers can respond to Page_Load events by implementing a handler in a script:
<script language="C#" runat="Server">
  void Page_Load (Object sender, EventArgs e)
  {
      // Insert custom page initialization code here
  }
</script>
A common use for Page_Load events is to query a database for information needed to initialize one or more of the page's controls. Page_Load can even be used to populate the page with controls programmatically.
      Because ASPX scripts execute in the context of a class derived from System.Web.UI.Page, they can call System Web.UI.Page methods and access System.Web.UI.Page properties. Those properties include Request, Response, Server, Application, and Session, which provide access to the ASP objects of the same name.
      The Page class also exposes a Boolean property named IsPostBack that's often used by Page_Load handlers. In many cases, initializations performed in Page_Load only need to happen when the page is requested anew, not during postbacks. IsPostBack tells you whether your code is executing within a postback (IsPostBack==true) or in response to a new request (IsPostBack==false). The following Page_Load handler initializes a control with the results from a database query, but only if it's called outside of a postback:
<script language="C#" runat="Server">
  void Page_Load (Object sender, EventArgs e)
  {
      if (!IsPostBack) {
          // TODO: Query database and initialize control
      }
  }
</script>
Such code is often used to avoid requerying a database (and reinitializing a form's controls) when postbacks occur.

Page-level Directives

      For the most part, the component of ASP.NET that compiles pages into executable formâ€"the page compilerâ€"does its work behind the scenes and without any input from you. However, you can add your two cents to the settings that it uses by including page-level directives in your ASPX files. Figure 9 lists the currently supported directives. The syntax for page-level directives is:
<%@ directive attribute="value" [...] %>
      For example, including the following directive at the top of an ASPX file turns tracing on.
<%@ Page Trace="true" %>
Tracing is a handy debugging aid that enables Web Forms to write trace output to Web pages. Similarly, the following statement enables tracing and identifies C# as the default language for scripts embedded within the page.
<%@ Page Trace="true" Language="C#" %>
For a complete description of all the options that ASP.NET places at your disposal through page-level directives, consult the document titled "ASP.NET Page Syntax".
      In some cases, page-level directives are optional. In certain scenarios, however, they're very much required. Web Forms that use custom controls, for example, require Register directives to define tag prefixes for those controls. You'll see examples of Register and other page-level directives used later in this article.

Separating Code and Data

      One feature that's made accessible by page-level directives is code-behind, which enables Web Form code and data to be placed in separate files. As an example, consider the mortgage calculator in Figure 7. MCalc.aspx contains a mixture of code (the OnCalculate method) and data (everything outside the <script> tag). If you want, you can separate the two by moving the code to a CS file. The problem then becomes how to marry the CS file and the ASPX file at runtime. The answer comes in the form of a Page directive.
      Figure 10 shows a modified version of the mortgage calculator that uses code-behind. This time, all the C# code is broken out into a separate file named MCalc2.cs. That file defines a class named CalculatePage that derives from Page (from System.Web.UI.Page, that is). In addition, the ASPX file now contains a Page directive whose Inherits attribute makes the CalculatePage class known to the page compiler, and whose Src attribute identifies the file in which the class is defined. When it compiles MCalc2.aspx, the page compiler doesn't derive from System.Web.UI.Page; instead, it derives from CalculatePage. The only oddity is that to connect the TextBox and Label controls declared in the ASPX file to the references to those controls in the CS file, TextBox and Label variables must be declared in CalculatePage and the variable names must match the control IDs specified in the ASPX file. That's why the following statements appear in MCalc2.cs.
protected TextBox Principal;
protected TextBox Rate;
protected TextBox Months;
protected Label Output;
      If you use Visual Studio.NET to generate your Web Forms, code-behind is employed automatically to get HTML in one file and C# or Visual Basic-based code in another. In the absence of a Page directive specifying the default language, the page compiler uses the file name extension to determine which compiler to use on a file identified with a Src attribute. If you changed the extension on MCalc2.cs to MCalc2.vb, the code would no longer compile because it would be passed to the Visual Basic.NET compiler rather than the C# compiler.

Controls

      The .NET Framework class library, which provides the classes common to all .NET applications, contains several classes that represent server controls. These classes are divided into two categories: HTML controls and Web controls.

Figure 11 System.Web.UI.HtmlControl
Figure 11 System.Web.UI.HtmlControl

      HTML controls are created from classes in the .NET Framework class library's System.Web.UI.HtmlControls namespace. All HTML control classes derive, either directly or indirectly, from System.Web.UI.HtmlControls.HtmlControl (see Figure 11). HTML control classes are instantiated by adding RunAt="server" to ordinary HTML tags. For example, the following statement declares a standard HTML text input field.
<input type="text">
But this statement declares an instance of HtmlInputText.
<input type="text" runat="server" />
Within an <input> tag of this type, you can use standard HTML attributes such as Name and Value. You can also use attributes that map to the properties defined in the corresponding HTML control class. For example, the statement
<input type="text" id="UserName" runat="server" />
assigns the value "UserName" to the HtmlInputText property named ID. This ID can be used to reference the control in server-side scripts. The following C# statement reads the text that the user entered into the control.
string strUserName = UserName.Value
      Figure 12 documents all the HTML control classes and the HTML tags to which they correspond. These classes are provided primarily to ease the chore of migrating existing Web applications (particularly ASP applications) to ASP.NET. For example, rather than replacing all instances of <input type="text"> with <asp:TextBox>, you can simply add RunAt="server" to the existing tags to convert them into living, breathing Web Forms controls.
      HTML controls are fine, but in truth, you don't need them. Why? Because Web controls do everything HTML controls do, and much more. Figure 13 shows the class hierarchy for Web controls. Most Web control classes derive either directly or indirectly from WebControl, which is a member of the .NET Framework class library's System.Web.UI.WebControls namespace. You've seen three of these classes in action already: Button, Label, and TextBox. But there are many others, each representing a different type of control that you can use in a Web Form.

Figure 13 Web Controls Hierarchy
Figure 13 Web Controls Hierarchy

      HTML controls are little more than glorified wrappers around existing HTML tags, but Web controls are richer and more ambitious in scope. For example, you can use a Calendar control to display calendars in Web Forms and let users pick dates using a visual (and self-contained) UI. Some Web controls even adapt themselves to the browser that they're rendered to. For example, a RequiredFieldValidator control rendered to an uplevel browser includes client-side script that validates user input locally. The same control rendered to a browser that doesn't support scripting, however, uses round-trips to the server to flag blank fields.
      The attributes that you can apply to tags when declaring Web controls are determined by the properties defined in the respective control classes. For example, because the TextBox class exposes properties named TextMode and Text, all of the following statements are valid:
<asp:TextBox Text="Hello" RunAt="server" />
<asp:TextBox Text="Hello" TextMode="singleline" RunAt="server" />
<asp:TextBox Text="Hello" TextMode="multiline" RunAt="server" />
<asp:TextBox Text="Hello" TextMode="password" RunAt="server" />
      The properties exposed by individual controls vary from control to control, but all Web controls, with the exception of Repeater, inherit a common set of properties from the base class WebControl. A partial list of those properties appears in Figure 14.
      Syntax is important when using these properties, particularly the Font, Width, Height, and XxxColor properties. The Font property has subproperties named Bold, Italic, Name, Names, Size, Strikeout, Underline, and Overline. To assign a value to a subproperty, separate the property name (Font) and the subproperty name with a hyphen, as in
<asp:Button Text="OK" RunAt="server"
 Font-Name="Verdana" Font-Bold="True" />
      The Font-Size property can be specified using pixels as the unit of measurement using either of the following syntactical conventions:
<asp:Button Text="OK" Font-Size="10"   
 RunAt="server" />
<asp:Button Text="OK" Font-Size="10px"   
 RunAt="server" />
Or it can be expressed in points by replacing px with pt:
<asp:Button Text="OK" Font-Size="10pt"    
 RunAt="server" />
      Width, Height, and BorderWidth values can be expressed in pixels, points, or percentages. Pixels is the default, so omitting px, pt, and % is the equivalent of writing out px.
<asp:Button Text="OK" Width="100" RunAt="server" />
<asp:Button Text="OK" Width="100px" RunAt="server" />
<asp:Button Text="OK" Width="100pt" RunAt="server" />
<asp:Button Text="OK" Width="100%" RunAt="server" />
      Color properties can be initialized using standard HTML color names (honeydew, mistyrose, oldlace, and so on) or hexadecimal RGB color values (such as #ffffff for white):
<asp:Button Text="OK" RunAt="server"
 BackColor="lightseagreen" ForeColor="#ffffff" />
      Most Web controls implement additional control-specific properties above and beyond those listed in Figure 14. For example, many of the code listings in this section use a property named Text to assign text to Buttons and TextBoxes. Text is not inherited from WebControl, but instead is declared in TextBox and Button. Consult the .NET SDK for a complete list of all the properties exposed by individual control types.
      Both HTML and Web controls support an event model that permits control events, such as pushbutton clicks, to be connected to server-side event handlers. You've seen one example of this already in Figure 7, where an OnClick attribute was used to connect the Calculate button to the OnCalculate method. The .NET SDK lists all the events defined by all the control types. In general, you can connect an event to a handler by prefixing the event name with On and using it as an attribute. For example, ListBox controls fire SelectedIndexChanged events each time the selection changes. The following statement connects SelectedIndexChanged events to a handler named OnNewSelection:
<asp:ListBox ID="MyListBox" RunAt="server"
  OnSelectedIndexChanged="OnNewSelection"
  AutoPostBack="true">
      Note the parameter that sets AutoPostBack equal to True. To avoid unnecessary round-trips to the server, ListBox selection changes only prompt postbacks if AutoPostBack is True. In the absence of automatic postbacks, a server-side script will only see SelectedIndexChanged events when the form is posted back to the server in response to other stimuli. AutoPostBack is supported by CheckBox, CheckBoxList, DropDownList, ListBox, TextBox, RadioButton, and RadioButtonList controls. In every case, it defaults to False. Don't forget to toggle AutoPostBack on if you want to handle events from these control types. Also, be aware that AutoPostBack does nothing in downlevel browsers that don't support JavaScript.
      Space constraints don't permit me to examine every one of the Web control classes in detail, but once you grasp the basics, the rest is easy to figure out. The following sections will give you a quick survey of the Web control classes in the .NET Framework class library and sample code showing how to use them in Web Forms applications.

Label Controls

      Label controls, which are denoted by <asp:Label> tags, display text in Web pages. You specify the control's text using System.Web.UI.WebControls.Label's Text property. The following statement creates a Label control and assigns it the text "Hello":
<asp:Label Text="Hello" RunAt="server" />
      To modify a Label control's text during the course of an application's execution, you can simply assign the control an ID and use a server-side script to write a new value to the control's Text property:
<asp:Label Text="Hello" ID="MyLabel" RunAt="server" />
  •••
// In a C# script
MyLabel.Text = "Goodbye";
This is the technique used in Figure 7 to display mortgage payment figures.

HyperLink Controls

      HyperLink controls let you place hyperlinks (the equivalent of <a> tags) in Web pages. Properties specific to HyperLink include Text, NavigateUrl, ImageUrl, and Target. Text specifies the control text, and NavigateUrl identifies the URL that the hyperlink points to.
<asp:HyperLink Text="Click here" RunAt="server"
  NavigateUrl="http://www.microsoft.com" />
      If you'd like, you can replace Text with ImageUrl to display the hyperlink as an image instead of a text string:
<asp:HyperLink ImageUrl="logo.jpg" RunAt="server"
  NavigateUrl="http://www.microsoft.com" />
      You can use the Target property to reference a window or frame at the URL named by NavigateUrl. For example, adding a "Target=_new" attribute to an <asp:Hyperlink> tag opens the resource in a new browser window.

Image Controls

      Image controls are to Web Forms as <img> tags are to HTML. Their purpose is to display images in Web pages. Control-specific properties include AlternateText, ImageAlign, ImageUrl, and Font. The following statement declares an Image control whose alternate text (the text displayed when the image file isn't available and when you mouse over the image) is "Company Logo" and whose appearance comes from Logo.jpg:
<asp:Image ImageUrl="logo.jpg" RunAt="server"
  AlternateText="Company Logo" />
      You can use the ImageAlign attribute to specify the image's alignment with respect to the text that surrounds it, and the Font property to change the font used for the alternate text.

TextBox Controls

      TextBox controls are the Web Forms equivalent of <input> and <textarea> tags in HTML and edit controls in Windows. They provide a way to solicit text input from users. Control-specific properties include Text, TextMode, MaxLength, Rows, Columns, Wrap, and AutoPostBack. Rows and Columns set the height and width of the TextBox in characters (rather than points or pixels). Rows is relevant only to multiline TextBoxes; it's ignored for single-line TextBoxes. The following statement creates a single-line TextBox control 16 characters wide that accepts up to 12 characters of input:
<asp:TextBox RunAt="server" MaxLength="12" Columns="16" />
      Setting TextMode to "password" tells the control to act as a password control by displaying asterisks instead of characters:
<asp:TextBox TextMode="password" RunAt="server" />
The "multiline" setting creates a multiline text input field:
<asp:TextBox TextMode="multiline"
  Rows="8" Columns="16" RunAt="server" />
      To read text from a TextBox control in a server-side script, simply read the control's Text property:
<asp:TextBox ID="MyTextBox" RunAt="server" />
  •••
// In a C# script
string strText = MyTextBox.Text;
      If the text in a TextBox has changed when the form is posted back to the server, the control fires a TextChanged event that can be handled by a script. The following example demonstrates how to synchronize the contents of a label control and a TextBox control by updating the label control each time a postback occurs. Note the AutoPostBack setting:
<asp:Label ID="MyLabel" RunAt="server" />
<asp:TextBox ID="MyTextBox" RunAt="server"
  AutoPostBack="true" OnTextChanged="OnUpdateLabel" />
  •••
<script language="C#" runat="server">
  void OnUpdateLabel (Object sender, EventArgs e)
  {
      MyLabel.Text = MyTextBox.Text;
  }
</script>
      Be aware that TextChanged events are not fired each time a new character is typed into the TextBox. AutoPostBack="true" causes a postback to occur only when the TextBox loses the input focus after its contents are modified. The Beta 1 documentation in the .NET SDK implies otherwise.

CheckBox and CheckBoxList Controls

      CheckBox controls add checkboxes to Web pages. Useful CheckBox properties include Text, TextAlign, and Checked. The following statement creates an unchecked checkbox:
<asp:CheckBox Text="Check me" RunAt="server" />
      This one creates a checkbox that's checked and whose text is aligned to the left (rather than the right) of the checkbox:
<asp:CheckBox RunAt="server" Text="Check me"
  Checked="true" TextAlign="left" />
      To check the state of a checkbox from a server-side script, read the Checked property, which is a Boolean:
<asp:CheckBox Text="Check me"
  ID="MyCheckBox" RunAt="server" />
  •••
// In a C# script
if (MyCheckBox.Checked)
    // Checked
else
    // Not checked
      CheckBox controls fire CheckedChanged events when they're checked and unchecked. Use OnCheckedChanged to connect CheckedChanged events to a handler implemented in a server-side script. Also, don't forget to set AutoPostBack to True, as you can see in Figure 15.
      The CheckBoxList control lets you display groups of checkboxes and exercise control over the group's layout. ListItem statements define the individual checkboxes within the group. Setting a ListItem's Selected property to True checks the corresponding checkbox:
<asp:CheckBoxList RunAt="server">
  <asp:ListItem Text="Checkbox 1" RunAt="server"
    Selected="true" />
  <asp:ListItem Text="Checkbox 2" RunAt="server" />
  <asp:ListItem Text="Checkbox 3" RunAt="server" />
</asp:CheckBoxList>
      Two CheckBoxList properties affect the layout of the checkboxes: RepeatColumns and RepeatDirection. RepeatColumns specifies the number of columns the checkboxes are to be divided into (default=1); RepeatDirection specifies whether the checkboxes are to be laid out in row-first order (RepeatDirection="horizontal") or column-first order (RepeatDirection="vertical"). Vertical is the default. Use the CellPadding and CellSpacing properties to fine-tune the spacing between checkboxes.

RadioButton and RadioButtonList Controls

      RadioButton controls (<asp:RadioButton>) enable users to select from a group of mutually exclusive options. RadioButtons behave very much like CheckBoxes (in fact, the RadioButton class even derives from CheckBox), but they add one important characteristic of their own: when one RadioButton is checked, the other RadioButtons in the same group are automatically unchecked. To support grouping, RadioButton adds one property, GroupName, to the list of properties it inherits from CheckBox. The following example creates two groups of RadioButtonsâ€"one containing three controls and the other containing twoâ€"and checks one RadioButton in each group:
<asp:RadioButton Text="Button 1" Checked="true"
  GroupName="Group1" RunAt="server" />
<asp:RadioButton Text="Button 2"
  GroupName="Group1" RunAt="server" />
<asp:RadioButton Text="Button 3"
  GroupName="Group1" RunAt="server" />
<asp:RadioButton Text="Button 4"
  GroupName="Group2" RunAt="server" />
<asp:RadioButton Text="Button 5" Checked="true"
  GroupName="Group2" RunAt="server" />
      To programmatically determine whether a RadioButton is selected, read the button's Checked property. To trap notifications indicating that a RadioButton's state has changed, use the OnCheckChanged and AutoPostBack attributes.
      RadioButtonList controls provide an alternate means for creating and grouping RadioButtons. The following code is equivalent to the previous code:
<asp:RadioButtonList RunAt="server">
  <asp:ListItem Text="Button 1" RunAt="server"
    Selected="true" />
  <asp:ListItem Text="Button 2" RunAt="server" />
  <asp:ListItem Text="Button 3" RunAt="server" />
</asp:RadioButtonList>
<asp:RadioButtonList RunAt="server">
  <asp:ListItem Text="Button 4" RunAt="server" />
  <asp:ListItem Text="Button 5" RunAt="server"
    Selected="true" />
</asp:RadioButtonList>
Note the lack of GroupName attributes. They're not needed with RadioButtonLists because grouping is implicit (each RadioButtonList constitutes its own group). Also be aware that like CheckBoxList controls, RadioButtonLists feature RepeatColumns and RepeatDirection properties that you can use to control the buttons' layout, as well as CellPadding and CellSpacing properties for tweaking their spacing. To find out which button in a RadioButtonList is selected, assign the RadioButtonList an ID and read its SelectedIndex property from a server-side script. SelectedIndex returns the zero-based index of the button that's selected.

ListBox and DropDownList Controls

      ListBox and DropDownList controls are analagous to <select> tags in HTML. Both present a list of strings for the user to select fromâ€"one in the form of a listbox, the other in the form of a dropdown list that resembles a combobox in Windows. Both controls inherit properties named SelectedItem and SelectedIndex from ListControl that permit server-side scripts to determine which item is currently selected. In addition, ListBox defines a property named SelectionMode (default="single") that can be set to "multiple" to create multiple-selection ListBoxes, and a property named Rows that sets the ListBox's height in rows.
      The following statements create a single-selection ListBox containing three items and select the second item:
<asp:ListBox ID="MyListBox" RunAt="server">
  <asp:ListItem Text="Item 1" RunAt="server" />
  <asp:ListItem Text="Item 2" RunAt="server"
    Selected="true" />
  <asp:ListItem Text="Item 3" RunAt="server" />
</asp:ListBox>
      These statements create a DropDownList containing the same items:
<asp:DropDownList ID="MyDropDownList" RunAt="server">
  <asp:ListItem Text="Item 1" RunAt="server" />
  <asp:ListItem Text="Item 2" RunAt="server" 
    Selected="true" />
  <asp:ListItem Text="Item 3" RunAt="server" />
</asp:DropDownList>
      This server-side script, written in C#, modifies a pair of Label controls whose IDs are "Label1" and "Label2" to report which items were selected from the lists:
Label1.Text = MyListBox.SelectedItem.Text;
Label2.Text = MyDropDownList.SelectedItem.Text;
      To permit a user to select multiple items from a listbox, add SelectionMode="multiple" to the <asp:ListBox> tag:
<asp:ListBox ID="MyListBox" SelectionMode="multiple" 
  RunAt="server">
      In a derived class, you can use the SelectedIndices property that ListBox inherits from ListControl to identify the items selected in a multiple-selection ListBox. But because SelectedIndices is declared protected rather than public, you can't use it with an ordinary ListBox. (Note: In Beta 2, SelectedIndices will probably change from protected to internal, in which case it wouldn't even be available in classes derived from ListBox.) To read the selection from a multiple-selection ListBox, use the control's Items collection to enumerate the ListBox items and check each item's Selected property. The method shown in Figure 16 will do just that and returns an integer array containing the zero-based indicies of all selected items.
      ListBoxes, DropDownLists, CheckBoxLists, and RadioButtonLists fire SelectedIndexChanged events upon the next server postback when the selection changes. You can add an OnSelectedIndexChanged attribute to a tag (for example, <asp:ListBox>) to wire up a handler. When the handler is activated, use the SelectedIndex or SelectedItem property to determine which item is currently selected.
      Sometimes it's useful to fill list controls programmatically, based on information gathered at runtime. Here's one way to populate a ListBox from a server-side script:
void Page_Load (Object sender, EventArgs e)
{
    if (!IsPostBack) {
        MyListBox.Items.Add ("Item 1");
        MyListBox.Items.Add ("Item 2");
        MyListBox.Items.Add ("Item 3");
    }
}
And here's another wayâ€"one that utilizes System.Collections.ArrayList:
void Page_Load (Object sender, EventArgs e)
{
    if (!IsPostBack) {
        ArrayList a = new ArrayList ();
        a.Add (new String ("Item 1"));
        a.Add (new String ("Item 2"));
        a.Add (new String ("Item 3"));
        MyListBox.DataSource = a;
        MyListBox.DataBind ();
    }
}
      This sample works because ListBox and other ListControl-derived classes have properties named DataSource that can be initialized with a reference to any object that implements an ICollection interface, and because ArrayList and many other collection types provided by the .NET Framework class library implement ICollection. Calling the control's DataBind method tells the control to enumerate the collection's items and to bind them by displaying them. I'll have more to say about data binding in the section on list-bound controls later in this article.

Button, LinkButton, and ImageButton Controls

      Three server controlsâ€"Button, LinkButton, and ImageButtonâ€"can be used to submit forms to the server to allow server-side processing to take place. All three control types do essentially the same thing; the difference is how they render themselves to the screen. Button controls resemble standard pushbuttons. LinkButtons look like hyperlinked text, and ImageButtons derive their looks from user-supplied images. When clicked, all three controls fire Command and Click events that can be handled in server-side scripts. In addition, ImageButtons transmit x and y coordinates revealing where in the image the click occurred.
      All three classes expose properties named CommandArgument and CommandName that can be used to customize the information passed in Command events. In addition, Button and LinkButton expose their text through Text properties. ImageButton lacks a Text property but offers ImageUrl and ImageAlign properties instead.
      The following code creates a Button and a LinkButton and connects them to a Click handler named OnSubmit:
<asp:Button Text="Button"
  OnClick="OnSubmit" RunAt="server" />
<asp:LinkButton Text="LinkButton"
  OnClick="OnSubmit" RunAt="server" />
    •••
<script language="C#" runat="server">
  void OnSubmit (Object sender, EventArgs e)
  {
      // TODO: Process form data
  }
</script>
      An ImageButton can't be connected to the same Click handler as a Button or LinkButton because its Click event is prototyped differently: it receives an ImageClickEventArgs rather than an EventArgs. If the handler wants to know exactly where the click occurred, it can obtain the x and y coordinates from the ImageClickEventArgs:
<asp:ImageButton ImageUrl="Logo.jpg"
  OnClick="OnSubmit" RunAt="server" />
    •••
<script language="C#" runat="server">
  void OnSubmit (Object sender, ImageClickEventArgs e)
  {
      int x = e.X;
      int y = e.Y;
  }
</script>
The coordinates encapsulated in an ImageClickEventArgs are measured in pixels and are relative to the upper-left corner of the ImageButton.

Table Controls

      Table controls (<asp:Table>) create HTML tables and, combined with TableRow and TableCell controls, provide a functional alternative to <table>, <tr>, <td>, and <th> tags. The following example creates a table containing two rows and two columns:
<asp:Table RunAt="server">
  <asp:TableRow>
    <asp:TableCell>Row 1, Column 1</asp:TableCell>
    <asp:TableCell>Row 1, Column 2</asp:TableCell>
  </asp:TableRow>
  <asp:TableRow>
    <asp:TableCell>Row 2, Column 1</asp:TableCell>
    <asp:TableCell>Row 2, Column 2</asp:TableCell>
  </asp:TableRow>
</asp:Table>
By default, a table defined this way has no border. To add a border, set the BorderWidth attribute to 1.
      If you'd like to add a background image as well, use the BackImageUrl attribute. BackImageUrl is one of several properties that Table adds to those it inherits from WebControl. Others include CellPadding, CellSpacing, GridLines, HorizontalAlign, and Rows. The TableRow and TableCell classes expose properties of their own that provide a high degree of control over the table's appearance and enable scripts to programmatically alter or enumerate a table's contents.
      The following creates a table identical to the previous one, but assigns text to the table's cells using TableCell's Text property:
<asp:Table RunAt="server">
  <asp:TableRow>
    <asp:TableCell Text="Row 1, Column 1" />
    <asp:TableCell Text="Row 1, Column 2" />
  </asp:TableRow>
  <asp:TableRow>
    <asp:TableCell Text="Row 2, Column 1" />
    <asp:TableCell Text="Row 2, Column 2" />
  </asp:TableRow>
</asp:Table>
Defining a table this way (and assigning IDs to TableCell controls) enables server-side scripts to easily modify a table's contents by changing the Text properties of individual TableCells. Also note that you can use TableHeaderCell controls in lieu of TableCells to define table headers. TableHeaderCell controls evaluate to <th> tags. Many browsers render <td> and <th> tags identically.

Panel Controls

      Panels are controls that are used to create logical groupings of other controls. A Panel generally has no UI of its own, but it is useful for controlling the visibility of other controls on the page. For example, suppose you declare three Label controls:
<asp:Label Text="1" ID="Label1" RunAt="server" />
<asp:Label Text="2" ID="Label2" RunAt="server" />
<asp:Label Text="3" ID="Label3" RunAt="server" />
To hide these Label controls, set their Visible properties to False:
Label1.Visible = false;
Label2.Visible = false;
Label3.Visible = false;
But if you grouped the Label controls with a Panel control, one statement would make all three disappear from sight:
<asp:Panel ID="MyPanel" RunAt="server">
  <asp:Label Text="1" RunAt="server" />
  <asp:Label Text="2" RunAt="server" />
  <asp:Label Text="3" RunAt="server" />
</asp:Panel>
•••
// In a C# script
MyPanel.Visible = false;

Calendar Control

      The controls that I've discussed thus far are little more than wrappers around simple HTML tags. Not so with the Calendar control. A single Calendar control expands to more than 100 lines of HTML when it's rendered to a browser.
      Calendar controls are ideal for letting users choose dates and date ranges using a highly visual UI. Getting a basic Calendar control up and running in a Web page is simplicity itself:
<asp:Calendar RunAt="server" />
The result is shown in Figure 17.
      But this simple example belies the sheer number of options that the Calendar class offers. Calendar defines 28 properties in addition to those it inherits from its base class. Many Calendar properties have subproperties that further expand the number of options available. These properties and subproperties let you customize the control's appearance in just about any way you like. They also enable you to get or set the date (or date range) selected in the control. The Calendar class also defines events named SelectionChanged and VisibleMonthChanged that allow server-side scripts to respond to selection changes and to changes in the month that is currently displayed.

Figure 17 Calendar Control
Figure 17 Calendar Control

      The ASPX file in Figure 18 is a full-blown Web Forms application that displays a stylized calendar and responds to SelectionChanged events by updating a Label control positioned just above the Calendar control. Clicking the Submit button activates a server-side script that reads the currently selected date from the control and displays it in the browser in "long date" format (see Figure 19).

Figure 19 Displaying Long Date
Figure 19 Displaying Long Date

AdRotator Control

      I won't say a lot about the AdRotator control other than to point out that it's functionally similar to the ad rotator control that comes with ASP. Its purpose is to display rotating banner ads using configuration parameters encoded in an XML file. For more information, consult the .NET SDK.

List-Bound Controls

      One of the tasks that Web applications are asked to perform most frequently involves retrieving data from a database and displaying it in a Web page. ASP.NET does several things to help out with this mundane but important chore. First, it interoperates with a new data access technology called ADO.NET that was specifically designed to meet the needs of data-handling applications deployed over the Web. Second, it genericizes the concept of a data source so applications can work with a wide range of data providers, from relational databases to in-memory XML data stores to simple arrays. Finally, it includes a family of Web controls that know how to read data from data sources and render visual representations to Web pages. Members of that family are known as the list-bound controls.
      Three of the classes in System.Web.UI.WebControls represent list-bound controls: Repeater, DataList, and DataGrid. A full treatment of these classes could fill a small book, but I want to give you a taste of what they're like, because in addition to being among the most complex classes in the .NET Framework class library, they're also some of the most usefulâ€"especially to developers building e-commerce applications.
      For starters, suppose you want to create a Web page that retrieves a set of records from a back-end database and displays those records in a table. You could use ASP and ADO to query the database and build the table yourself, or you could use ADO.NET and a DataGrid control and let the DataGrid build the table for you (see Figure 20). The database used in this example is the Pubs database that comes with the .NET SDK. The page's Page_Load handler uses a SQL SELECT command to query the database for a list of all the records in the Titles table. (Note the if clause that prevents the query from being performed during postbacks.) Each record returned from the query contains information about one bookâ€"its title, price, publication date, and so on. The statement
  MyDataGrid.DataSource =   
    ds.Tables["Titles"].DefaultView;
connects the results of the query to the DataGrid control, and the statement
MyDataGrid.DataBind ();
binds the control to the data. The DataGrid itself is declared with an <asp:DataGrid> tag and assigned the ID MyDataGrid.
      Figure 21 shows the resulting Web page. The DataGrid control renders back to the browser as a standard HTML table containing all the data returned by the query, which currently consists of all the rows and columns (including column names) in the Titles table of the Pubs database.

Figure 21 DataGrid Control
Figure 21 DataGrid Control

      That's not bad for a start, but I can do better. Right now the table shows far more information than it needs to, and it could definitely be formatted more attractively. Plus, if I want customers to buy books from my Web page, they'll need a way to add items to a shopping cart. I won't go so far as to implement a full-blown shopping cart, but I'll at least lay the groundwork for you.
      The new and improved DataGrid demo appears in Figure 22. The <asp:DataGrid> tag now includes a long list of attributes used to customize the table's appearance. The AutoGenerateColumns attribute is particularly important, because setting it to False prevents the DataGrid from automatically generating columns based on the fields it finds in the database. Now I can control the columns displayed by adding <asp:BoundColumn> and <asp:ButtonColumn> tags to the <asp:DataGrid> tag. A BoundColumn is a DataGrid column that is bound to a particular field in the databaseâ€"specifically, to the field identified by the BoundColumn's DataField property. A ButtonColumn contains buttons instead of ordinary text. This ButtonColumn inserts an "Add to Cart" command into each row of the table. Clicking a button activates the event handler, OnItemAction, which displays the name of the item that the user selected at the bottom of the page (see Figure 23).

Figure 23 Selecting an Item
Figure 23 Selecting an Item

      The many attributes used in the <asp:DataGrid> are emblematic of the myriad formatting options that the DataGrid class offers. In particular, note how the control's HeaderStyle, ItemStyle, and AlternatingItemStyle properties (and their subproperties) are used to customize the appearance of the rows. Also note how ItemStyle-HorizontalAlignment is used to right-align the numbers in the Price column and center the buttons in the Action column, and how DataFormatString is used to format the numbers in the Price column as currency values. Unlike Windows-based controls, which offer an extremely limited number of formatting options, DataGrid controls put you in charge of virtually every aspect of their appearance.
      These examples barely scratch the surface of what you can do with DataGrid controls, and they don't even address DataList and Repeater controls. But hopefully you get the idea. List-bound controls ease the chore of displaying structured data. The more you use ASP.NET, the more you'll appreciate the power of these controls. For more information about list-bound controls and examples demonstrating how to use templates to further customize their appearance, read "Using the ASP+ List-Bound Controls".

Validation Controls

      The Web controls family includes a set of controls whose purpose isn't to solicit input, but to validate it. Consider the mortgage calculator presented earlier in this article. A real-life version should display an error message if the user fails to fill in a field or fills it in improperly. That's what validation controls are for.
      The revised mortgage calculator in Figure 24 uses RequiredFieldValidator controls to check for blank fields, and RegularExpressionValidator controls to make sure that entries are well-formedâ€"specifically, that the Principal and Months fields contain only numbers and that the Rate field contains numbers and a period. RequiredFieldValidator controls verify that the content of the controls that they're attached to is non-null, while RegularExpressionValidator controls validate a control's content against a regular expression provided by the programmer. (Unfortunately, RegularExpressionValidator controls can't be used to ensure that the fields are also filled in.) For example, setting a RegularExpressionValidator's ValidationExpression property to [0-9]* specifies that any number of digits (and digits only) will be accepted; setting it to [0-9]\.[0-9]* limits valid text to strings of the form *.*, where * is any numeric character.
      Figure 25 shows what happens if the Calculate button is clicked but an entry is missing: an error message flags the offending field. You control the error message and its placement. Among other things, this means that you no longer need code in OnCalculate to check for null strings. If the Calculate button is clicked and a field is blank, the form is never submitted, therefore the script isn't executed.

Figure 25 Validating Input
Figure 25 Validating Input

      How do validation controls work? As you can see in Figure 24, each TextBox control now has corresponding RequiredFieldValidator and RegularExpressionValidator controls. The table used to align the form's control has been extended with a third column that hosts the validators. Before rendering themselves to the output stream, validator controls check to see whether the browser that they're rendering to supports scripting. If the answer is yes, they return client-side script that performs validation checking locally. If the answer is no, they omit the client-side script and return HTML that forces a return trip to the server so the server can do the checking. Either way, you win. You get a page that works no matter what kind of browser is being used. And you get a page that works more efficiently with intelligent browsers.
      In addition to the RequiredFieldValidator and RegularExpressionValidator controls, the .NET Framework also provides:
  • CompareValidator control, which validates input by comparing it to a value in another control or a value that you specify.
  • RangeValidator control, which verifies that an input value falls within a specified range.
  • CustomValidator control, which validates input using an algorithm you supply.
  • ValidationSummary control, which displays a summary of all the validation errors encountered on a page. For more information regarding these controls, visit MSDN® Online's Web Forms Validation page.

Custom Controls

      It should be abundantly clear by now that the System.Web.UI.WebControls namespace includes a rich variety of Web controls that ease the chore of building sophisticated Web Forms. But there's more. If none of the existing controls fit the bill, you can write Web controls of your own. Such controls are variously referred to as custom controls, custom server controls, or custom Web controls. A full treatment of custom controls merits an article of its own, but a basic example appears in Figure 26.
      This example, Headline.aspx, is a simple Web Form that employs a custom control named Headline. The Register directive equates the tag prefix "demo" to the namespace MSDNMagControls. The source code for the Headline control is contained in Headline.cs. That file declares a namespace named MSDNMagControls, which contains a class named Headline. Headline is derived from System.Web.UI.Control, which forms the basis for all server controls. To render the Headline control to the browser, the framework calls the control's virtual Render method and passes a reference to an HtmlTextWriter object the control can use to write text to the HTML output stream. Headline overrides the Render method and outputs the text stored in a field named _Text, which is exposed through a property named Text, surrounded by <h1> tags. The result? In Headline.aspx,
<demo:Headline Text="Hello, world" RunAt="server" />
is equivalent to the HTML syntax:
<h1>Hello, world</h1>
However, the actual rendering is done by the control. Headline could be extended with additional properties, methods, and even events to make it a first-class Web control.
      Something that's not obvious from the source code figures is how the ASPX file knows where to find the compiled CS file containing the custom control. In order for this example to work, you must compile the CS file into a DLL and store it in a directory named \bin under the application's virtual root directory. The following command uses the C# compiler to compile Headline.cs, creating a DLL named MSDNMagControls.dll:
csc /t:library /out:MSDNMagControls.dll
  /r:System.Web.dll Headline.cs
      Once the DLL is created, placing it in the \bin directory makes it available to Web Forms that are part of the corresponding app .

User Controls

      So far the term "control" has referred either to HTML controls or Web controls. Web Forms support a third type of control, which the documentation refers to as user controls. A user control is a chunk of reusable Web Forms code packaged in an ASCX file. Generally, it's all or part of a form without the <form> tags. To employ a user control, you open an ASPX file and add a Register directive that registers a tag name and tag prefix for the user control and identifies the user control's ASCX file. You then declare an instance of the user control by inserting a tag containing the user control's tag name and prefix into a form in the ASPX file.

Figure 27 User Control Login Screen
Figure 27 User Control Login Screen

      The login form shown in Figure 27 is built around a user control. The user control contributes the part of the form that appears between the horizontal rules. Everything else comes from the ASPX file (see Figure 28). In Login.aspx, this statement registers the user control.
<%@ Register TagPrefix="demo"
  TagName="LoginForm" src="Login.ascx" %>
This statement declares an instance of it and initializes its background color.
<demo:LoginForm ID="LoginForm" BackColor="#ccccff"
  RunAt="server" />
BackColor is a valid attribute because the script in Login.ascx implements a property of that name and maps it to the BackColor property of the table used to align the user control's controls. The ASCX file also defines properties named UserName and Password. UserName is used in the page's Page_Load handler to read the name that the user entered.
      User controls let you package snippets of Web Forms in such a way that they can be reused as components in other Web Forms. Additionally, user controls can contribute more than just a user interface. The user control in Login.ascx includes validation logic that rejects the login (prevents the form from being submitted) if either input field is blank, if the user name contains less than five characters, or if the password contains less than eight. In the real world, a user control such as this one could be enhanced to perform real authentication. Then, building a screen that knows how to validate logins would be as simple as adding the user control to a form.
      As a syntactical matter, note that unlike ASPX files, ASCX files can't include Page directives. They can, however, contain Control directives that accomplish the same objective.

Conclusion

      That's the Web Forms programming model in a nutshell. I believe that Web Forms are the most important feature of Microsoft .NET, and that they will be the number one reason that most early adopters of .NET will embrace the new platform. If I'm right, you can expect to see many more articles discussing Web Forms and other components of ASP.NET in future issues of MSDN Magazine.
Jeff Prosise makes his living programming Windows and teaching others how to do the same. He is also a cofounder of Wintellect, a developer training and consulting firm that specializes in .NET developer training. To contact Jeff, send e-mail to jeffpro@wintellect.com.

From the May 2001 issue of MSDN Magazine

Page view tracker