2.5 Web Forms and Code-Behind


Perhaps the most appealing aspect of the Web Forms model is that in combination with code-behind, it enables true separation of page logic from page layout and rendering. For example, recall the page shown in Listing 2-1, where the input and select elements were marked with the runat =server attribute, enabling state retention and server-side manipulation of those elements. Although this was helpful, our .aspx page was more than pure layout. It included server-side script to print a message, and we statically populated the options of the select element. Using code-behind with Web forms, we can very often remove all code from our .aspx pages, creating a clean partitioning of form logic and form layout. Listing 2-10 demonstrates this technique by showing the same page displayed in Listing 2-1 but now rewritten with a code-behind file, which is shown in Listing 2-11.

Listing 2-10 Sample Page with Server-Side Controls and Code-Behind
 <! WebFormPage2.aspx > <%@ Page Language="C#"          Inherits="EssentialAspDotNet.WebForms.Page2"          src="Page2.cs" AutoEventWireUp="false" %> <html> <body>   <form runat=server>     <h3>Enter name:         <input type=text id=_name runat=server/></h3>     <h3>Personality:         <select id=_personality runat=server /></h3>      <input type=button id=_enterButton              value="Enter" runat=server/>     <p runat=server id=_messageParagraph />   </form> </body> </html> 
Listing 2-11 Code-Behind File for Sample Page
 // Page2.cs using System; using System.Web; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; namespace EssentialAspDotNet.WebForms { public class Page2 : Page {   protected HtmlSelect         _personality;   protected HtmlInputText      _name;   protected HtmlInputButton    _enterButton;   protected HtmlGenericControl _messageParagraph;   override protected void OnInit(EventArgs e)   {     // Wire up handler to ServerClick event of button     _enterButton.ServerClick += new EventHandler(OnEnter);   }   override protected void OnLoad(EventArgs e)   {     // On initial access, populate select with items     if (!IsPostBack)     {       _personality.Items.Add(new ListItem("extraverted"));       _personality.Items.Add(new ListItem("introverted"));       _personality.Items.Add(new ListItem("in-between"));     }   }   protected void OnEnter(object src, EventArgs e)   {     // When the user presses enter, print a message     string msg = string.Format("Hi {0}, you selected {1}",                       _name.Value, _personality.Value);     _messageParagraph.InnerText = msg;   } } } 

Note that we were able to manipulate server-side controls on the form from fields declared in our code-behind class. In fact, looking just at the code-behind file, it appears that we are manipulating uninitialized fields in our class, because the _personality , _name , _enterButton , and _messageParagraph fields are never explicitly created but are definitely used. If you look closely, you will notice that these field names match exactly the identifiers of their corresponding server-side controls in the .aspx file. This is an important relationship that you will use almost anytime you work with Web forms and code-behind classes. When you declare a field, either protected or public, with the same name as the identifier of a server-side control in your form, that field is initialized with a reference to that server-side control when the class is created. It is also crucial that the field be of the correct type ”in our case we were mapping to four different HTML control types and had to carefully declare each field with the correct type, matching it to the element on the form to which it corresponds. We discuss this mapping of server-side HTML elements to classes in more detail in the upcoming HtmlControls section.

This process of associating server-side controls with fields in a Page -derived class occurs during the parsing of the .aspx page. The parser must be careful not to redefine fields in the class that is generated from the .aspx file, because this would mask any fields declared with the same name in the code-behind base class. Instead, the parser uses reflection to query the code-behind base class during the parsing of the .aspx file. If there is a public or protected field declared in the code-behind base class whose name matches the identifier of the server-side control, it will not generate a field for that control in the generated class. If there is no such field in the code-behind base class, it will create a field in the newly generated class. This guarantees that all server-side controls have a corresponding field in the generated class, either inherited from the code-behind base class or declared directly in the generated class. This is also why the code-behind base class must declare these fields as either public or protected, so that the derived class can access them and assign the newly created control references to them.

Figure 2-6 shows this field binding. In this example, the Test.aspx file contains three server-side controls: the form, which has no explicit identifier, the server-side span element named _foo , and the server-side input element named _bar . The code-behind class, BasePage , contains a single protected field named _foo of type HtmlGenericControl , which is what a span element maps to. Thus, when the parser generates the class from the Test.aspx file, it adds two fields to the derived class: one for the form control with an artificially generated identifier ( _ctl0 ) and the other using the _bar identifier assigned in the page.

Figure 2-6. Binding Fields to Server-Side Controls

graphics/02fig06.gif



Essential ASP.NET With Examples in C#
Essential ASP.NET With Examples in C#
ISBN: 0201760401
EAN: 2147483647
Year: 2003
Pages: 94
Authors: Fritz Onion

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net