Microsoft Visual J# .NET (Core Reference) (Pro-Developer)
I l @ ve RuBoard |
Now that you've learned how to create Web Forms and other ASP.NET pages, let's look in more detail at the Page class, its life cycle, and how to use controls in conjunction with a Page . The Page Class
Every ASP.NET page has an associated Page class. This class can be created from an ASPX page that contains a mixture of HTML and code, or it can be formed from the merger of automatically generated code and a code-behind class (as described earlier). In either case, the attributes of the <%@ Page %> directive provide some key information when this class is created, as shown in Table 16-1. Table 16-1. Important Attributes of the <%@ Page %> Directive
Each page can have only one <%@ Page %> directive, but it can appear anywhere on the page. This differs from ASP, where all directives must be on the first line. Intrinsic Objects and Properties
As in ASP, certain HTTP- related functionality is available through the properties and methods of the Page class in ASP.NET. ASP employs the concept of intrinsic objects that are abstractions of important underlying concepts, including
The Page class also provides a Controls collection property that allows programmatic access to the child controls of the page. Some of the information set using the <%@ Page %> directive is also accessible programmatically, such as the ErrorPage property. You can change such properties as the context of your application changes.
Note If you're not subclassing the Page class, you can access the intrinsic objects using the HttpContext object. Simply call the static HttpContext.get_Current method to retrieve your HttpContext .
Events and Life Cycle
The Page class has certain events that fire during its life cycle. All of the events generated by a Page are inherited from the Control or TemplateControl classes. (The Page is just a specialized form of Control .) The most commonly used ones are the Load and Unload events. In FeedsHowMany.aspx.jsl (version 2), you might have noticed the InitializeComponent method: privatevoidInitializeComponent() { this.Calculate.add_Click(newSystem.EventHandler(this.Calculate_Click)); this.add_Load(newSystem.EventHandler(this.Page_Load)); } Visual Studio .NET uses the InitializeComponent method to connect events to event handlers for the page (the same technique and method used for Windows Forms applications). As you can see, in this example two event handlers are hooked up, one for the Load event on this (the current Page instance) and one for the Click event on the Calculate Button . A System.EventHandler delegate is added to the list of delegates stored in the Load event through the add_Load call. This EventHandler refers to the Page_Load method, which you can use to perform page-specific initialization: privatevoidPage_Load(System.Objectsender,System.EventArgse) { //Initializationhere... } In this case, the event handlers are programmatically associated with events. ASP.NET also supports a feature called automatic event wire-up . This takes the form of a property on the <%@ Page %> directive called Auto EventWireup . If AutoEventWireup is set to true (the default, if not explicitly defined), the ASP.NET runtime will look for standard method names (such as Page_Load or Page_Init ) that match the events for this page and automatically invoke them when that event occurs, regardless of any event hookups. This is convenient if you can use the standard method names, but don't use it in conjunction with manual hookups of the same events to the same handlers because this will cause the handler to be invoked twice.
Note By default, Visual J# .NET sets AutoEventWireup to false and connects events to event handlers in the InitializeComponent method, as previously shown.
The Load event is triggered every time the page is loaded. Note that an instance of the page is loaded and unloaded for every client request. The Page instance is used for the duration of that request and is then discarded. This means that instance data will not be retained between invocations. For example, if you wanted to keep a count of the number of times a page has been visited by a client, you could add a counter that's displayed using a Label : protectedSystem.Web.UI.WebControls.LabelCount; privateintcount=0; privatevoidPage_Load(System.Objectsender,System.EventArgse) { Count.set_Text("Count: " +++count); } Unfortunately, this would display 1 every time you accessed it because the value of the count variable would be thrown away every time the page was unloaded. If you want to maintain state between client requests , you should use the instance of System.Web.SessionState.HttpSessionState provided through the Page object's Session property. This is discussed in detail later in the chapter. The life-cycle events on an ASP.NET page exhibit a minor side-effect when you work with Web Forms. Web Forms pages post their data back to themselves , and some of the processing of this data might be performed in the Load event handler. But this handler is called every time the page is loaded ”even the first time, before the user has had a chance to fill out the form. Any tasks that are based on the content of the form should not be performed until the user has submitted some information. To get around this, the Page class has an IsPostBack property that tells you whether the current page is being loaded and processed as the result of a form being posted to it or whether this is the initial display of the form. You can use this property to prevent form-based code from being executed the first time a Web Form is called: privatevoidPage_Load(System.Objectsender,System.EventArgse) { if(this.get_IsPostBack()) { //Eventcalledastheresultofapostback. //Processthecontentsoftheform } } Common Controls
When you use Web Forms to create user interfaces, you need various types of controls that the user can interact with. You've seen that two types of server-side controls are available for building interfaces ”HTML controls and Web controls. Web controls are the more powerful mechanism and are the standard type of control used in most ASP.NET applications. In Visual Studio .NET, you can drag Web controls from the Toolbox onto the design area for your page, set their properties, and set handlers for any events that they might raise. The Web controls can be found in the System.Web.UI.WebControls namespace. You've already learned how to build a simple user interface using Button , TextBox , and Label controls. This section takes a brief tour of some of the other common controls you might want to use. (This is by no means an exhaustive list!) Forms and Selection
You can use various server-side controls as part of a form to allow a user to enter information, select options, or indicate actions, including:
For more information about these controls, see the .NET Framework documentation. Displaying Information
You can choose from a selection of controls for displaying information to the user. They include
For more information about these controls, see the .NET Framework documentation. Controlling Layout
When you define an ASP.NET page, you can choose between relative and absolute positioning of controls. Relative positioning uses something called flow layout , which places the controls next to each other across the page. If the combined width of the controls is greater than the width of the page, the layout will "flow" to a new row underneath, until all of the controls are visible. If the user resizes the form at run time, the positions of the controls will be adjusted automatically so none of them is truncated or hidden. This layout works on the same principle as the FlowLayout in the Abstract Window Toolkit (AWT). The alternative is to use a grid layout , which is the default for Web Forms. This layout allows you to position controls in a precise location, but if a user resizes the form at run time, controls might disappear from view. You can set the type of layout used by changing the pageLayout property associated with that page in Visual Studio .NET. Note that some controls, such as Literal controls, will not position themselves in a grid layout. In this case, you can add a Panel control to the grid and then place the offending controls within the Panel . This mechanism is also useful for user controls (described next). Creating Your Own Controls
The standard functionality of ASP.NET Web Forms is powerful, but it doesn't always meet application-specific requirements. If necessary, you can create your own controls for use in your ASP.NET application. You can create your own server-side controls that you can use in the same way as those provided with the .NET Framework, but the details (although not rocket science) are beyond the scope of this chapter. If you have an application requirement for a slightly specialized version of an existing control, however, or for a common group of controls that can be used in multiple places (such as a navigation bar with multiple buttons, images, and labels), a user control might be the answer. Creating a User Control
A user control consists of one or more Web controls placed in an instance of the System.Web.UI.UserControl class. You can create a user control in Visual Studio .NET by selecting Web User Control in the Add New Item dialog box. (There are other ways to create user controls, which you can pursue by referring to the .NET Framework documentation.) You'll see a design area similar to that for a Web Form. You can add controls as needed to create your user control. If you want to add custom code to your user control, you can access the code-behind and add methods as appropriate. For example, suppose you want to create a navigation bar for the Fourth Coffee online store. It will contain a label for the Fourth Coffee Web site and several navigation buttons for Home, Back, and so forth. You can start by creating a user control in Visual Studio .NET. Choose the Add Web User Control option from the Project menu. By default, the user control uses a flow layout, so to obtain more precise positioning, you can drag and drop a GridLayoutPanel from the HTML section of the ToolBox onto the design surface of your user control and then resize it as appropriate. You can then drag and drop your Web controls, such as buttons, labels, and images, onto the GridLayoutPanel and add their event-handling code as appropriate. One of these buttons can be a Help button that takes the user to a page containing context-sensitive help. The target URL for this button would have to change from page to page because the context would change. The easiest way to do this is to provide a property, such as HelpUrl , on your user control class, as shown in the sample file Navigation.ascx.jsl listed here. Navigation.ascx.jsl
packageFourthCoffee; importSystem.*; importSystem.Data.*; importSystem.Drawing.*; importSystem.Web.*; importSystem.Web.UI.WebControls.*; importSystem.Web.UI.HtmlControls.*; /** *SummarydescriptionforNavigation. */ publicabstractclassNavigationextendsSystem.Web.UI.UserControl { protectedSystem.Web.UI.WebControls.LabelLabel1; protectedSystem.Web.UI.WebControls.ButtonHomeButton; protectedSystem.Web.UI.WebControls.LabelLabel2; protectedSystem.Web.UI.WebControls.ButtonHelpButton; privateSystem.StringhomeUrl= "default.htm"; privateSystem.StringhelpUrl=null; /**@property*/ publicvoidset_HelpUrl(System.Stringurl) { if(url!=null&&url.get_Length()!=0) { helpUrl=url; HelpButton.set_Enabled(true); } } /**@property*/ publicSystem.Stringget_HelpUrl() { returnhelpUrl; } privatevoidPage_Load(System.Objectsender,System.EventArgse) { //Putusercodetoinitializethepagehere if(helpUrl==null) { HelpButton.set_Enabled(false); } } #regionWebFormDesignergeneratedcode protectedvoidOnInit(System.EventArgse) { // //CODEGEN:ThiscallisrequiredbytheASP.NETWebFormDesigner. // InitializeComponent(); super.OnInit(e); } /** *RequiredmethodforDesignersupport-donotmodify *thecontentsofthismethodwiththecodeeditor. */ privatevoidInitializeComponent() { this.HomeButton.add_Click(newSystem.EventHandler(this.HomeButton_Click)); this.HelpButton.add_Click(newSystem.EventHandler(this.HelpButton_Click)); this.add_Load(newSystem.EventHandler(this.Page_Load)); } #endregion privatevoidHomeButton_Click(System.Objectsender,System.EventArgse) { GoToPage(homeUrl); } privatevoidHelpButton_Click(System.Objectsender,System.EventArgse) { GoToPage(helpUrl); } privatevoidGoToPage(System.Stringpage) { if(page.EndsWith(".aspx")) { get_Server().Transfer(page); } else { get_Response().Redirect(page); } } } Using a User Control
Once you've defined a user control, you can add it to other pages by registering it in the ASPX file of each host page. The following registration directive, used in the sample file Login.aspx, indicates that the tag Navigation , prefixed by FourthCoffee , refers to the class contained in the user control sample file Navigation.ascx: <%@RegisterTagPrefix="FourthCoffee" TagName="Navigation" src="Navigation.ascx" %> Within the host page, you can use the registered tag to indicate where the control should be positioned. The control declaration itself must be placed within the form for the page (<form runat ="Server"> ). Because the user control does not automatically work with grid layouts, if you're using a grid layout and you want to position the control in a precise location, you can place the control in a Panel Web control and then place the Panel within the form: <asp:Panelid="Panel1" runat="server" Height="81px" Width="572px"> <FourthCoffee:Navigationid="navBar" runat="server"> </FourthCoffee:Navigation> </asp:Panel> The user control will be displayed within the host page, just like any other Web control. You can see this in Figure 16-14, which shows the Login.aspx page with the Navigation user control visible at the bottom. (It contains the Home and Help buttons together with the logo "Welcome to Fourth Coffee, Your handy cake supplier.") Figure 16-14. An ASP.NET User Control can be used to group common controls in a single entity.
If your user control contains custom functionality, such as the HelpUrl property discussed previously, you'll want to access this programmatically. Within the host page, you can add code to find the user control within the Panel and set its property, as shown here: NavigationnavBar=null; IEnumeratorenumerator=Panel1.get_Controls().GetEnumerator(); while(enumerator.MoveNext()) { Controlctrl=(Control)enumerator.get_Current(); System.StringcontrolName=ctrl.GetType().get_Name(); System.StringcontrolName1=ctrl.GetType().get_FullName(); if(controlName.CompareTo("Navigation_ascx")==0) { navBar=(Navigation)ctrl; break; } } navBar.set_HelpURL("LoginHelpPage.htm"); You can find this code in the PageLoad method of the sample file Login.aspx. This sample file also contains session and cookie manipulation (covered later). Binding to Data
As mentioned in the previous section, some of the Web controls are intended for use with ADO.NET data sources. These controls are associated with, or bound to , a data source so that when they're rendered they reflect the contents of that data source. Again, an exhaustive examination of data binding to Web controls is outside the scope of this chapter, but we'll give you an idea of what you can do and how to perform simple data binding in J#. You can do many more things, such as paging through large amounts of data and handling events generated by user interaction. Binding XML
As an example of data binding, consider the use of a DataGrid as a means of displaying the contents of the Fourth Coffee cake catalog. Given the catalog data in an ADO.NET DataSet , the DataGrid can generate a representation of one of the tables in the DataSet . The DataGrid will infer column names based on the columns in the underlying table. By default, the DataGrid will display the first table in the DataSet . To display another table, you can set the DataMember property of the DataGrid to that table. A simple way to create an ADO.NET DataSet to which you can bind a DataGrid is to base one on an XML document. Recall from Chapter 5 and Chapter 7 that an ADO.NET DataSet leads a secret double life as an XmlDataDocument . Use this fact by loading XML into the DataSet and then binding the DataSet to a control. Consider the XML document in the CakeCatalog.xml sample file, shown below. This document maps to a DataSet comprising three tables, whose names are inferred from the schema of the XML document:
To display this data, we created a simple Web Form called ShowXmlCatalog.aspx in the FourthCoffee project, which contains two DataGrid controls. In the code-behind file ShowXmlCatalog.aspx.jsl, the XML document in the file CakeCatalog.xml is loaded into the DataSet called xmlCatalog . The application uses the MapPath method of the HttpServerUtils object to ensure that the filename is correct relative to the current virtual directory. The DataSet is then assigned to the DataSource property of two DataGrid controls. One DataGrid will display the cake type information, and the other will display the size options. To do this, the DataMember property is set to the appropriate inferred table name ( CakeType and Option , respectively) and then the DataBind method is called. You will find the complete ShowXmlCatalog.aspx.jsl file in the FourthCoffee sample project. The result of this data binding is shown in Figure 16-15. Figure 16-15. Simple data binding using a DataGrid and an XML document
All of this binding code is performed in the Page_Load method. If you've cached the DataSet when the page is first loaded or if you're binding different data based on user feedback, you might want to check the IsPostBack property before performing data loading or binding. Binding SQL Data
As you've seen, the DataSet representation of the XmlDataDocument allows an XML document to be bound to a control. Hence, any binding you saw in the previous section can be performed equally well with a DataSet populated with data obtained from any other form of underlying data source. You can also use a DataReader as a data source for the data binding of Web controls. This can be more efficient than using a DataSet when the data in question is read-only and cannot be cached and therefore must be retrieved every time. |
I l @ ve RuBoard |