Web Forms Applications

for RuBoard

One of the great things about ADO.NET is that is can be used efficiently in the presentation services tier of both Windows Forms and Web Forms (ASP.NET) applications even though the two programming models differ greatly behind the scenes. You've probably already gotten an understanding of this fact if you followed the discussion on Day 2, "Getting Started."

In this section, you'll learn how data binding works in Web Forms applications and both how to manage the state of your data and validate it. You can find the controls and other types discussed in this section in the System.Web.UI namespace.

Using Data Binding

Right from the start, it should be noted that data binding in Web Forms applications is much different than in Windows Forms applications because it relies on two key assumptions not present in Windows Forms applications:

  • Most data is read-only.

  • Web applications are stateless.

From these two assumptions, everything else flows. First, the read-only assumption means that in Web Forms data binding, the value from the data source is pulled into the control as the page is built, but it isn't automatically pushed back to the data source when the page is submitted back to the server. Although you can certainly update a data source from a bound control, Web Forms data binding won't do it for you. Because Web Forms data binding is read-only, it also makes sense to use not only DataSet and DataView objects for binding, but also data readers.

Second, the stateless nature of HTTP and thus Web applications means that Web Forms data binding has no concept of BindingContext and CurrencyManager objects that automatically track the state of the bound controls and the position within the data source.

Once again, this information is available, but you have to manually position the controls, as shown in Listing 2.3 on Day 2. As you'll see, this also has implications for balancing the number of roundtrips to the data store your application will incur against the overhead of storing this state information. The stateless architecture of the Web also fits nicely with the disconnected nature of ADO.NET. As we discussed on Day 4, this was one of its design goals.

To act as a provider for data binding to a collection of objects, a class simply needs to implement the IEnumerable interface, which supports a simple iteration over a collection of objects. This interface is itself implemented by the IList interface, so approximately 100 classes in the framework can all be bound to Web Forms controls. These classes include collection classes such as Array , ArrayList , SortedList , Queue , and Hashtable , as well as the ADO.NET DataSet , DataTable (once again through the IListSource interface), and DataView , and data readers such as OleDbDataReader .

Of course, as in Windows Forms, in addition to the standard properties of controls such as Text , any property or field of the controls or the page itself can consume data from a data source both graphically at design time and programmatically at run time.

In the following sections, you'll learn how to use simple binding (referred to as single-value binding) and complex binding (referred to as multi-record binding) in Web Forms applications.

Single-Value Binding
graphics/newterm.gif

Single-value binding enables you to bind any property of any control to an expression. This can be done by using the DataBindings dialog in VS .NET, by editing the HTML directly, or using the DataBinding event exposed by each control (inherited from System.Web.UI.Control ) and the page ( System.Web.UI.Page ) itself.

In the simplest case, you can drag and drop a Web Forms control from the toolbox on a Web Form and then open the DataBindings dialog shown in Figure 16.4 by clicking on the ellipsis in the Properties window. This technique comes in handy when you're using strongly typed DataSet objects because they'll appear in the box under the Simple Binding radio button. It's a simple matter to drill down into the DataSet and select the column to bind to. This is shown in Figure 16.4 where the Address column of a strongly typed DataSet called CustomersDs1 is being bound to a TextBox control.

Figure 16.4. Data binding in a Web Form. You can use this dialog to specify single-value binding in a Web Form.

graphics/16fig04.jpg

One of the things you'll notice in Figure 16.4 is that as you drill down into the DataSet and underlying DataView , you're automatically specifying a row (in this case, the first row) to bind to. This is the case because the Web Form doesn't have any concept of a CurrencyManager , so you need to explicitly bind to a row.

Note

When a property is bound with an expression, it will appear with a yellow barrel icon in the Properties window and in the DataBindings dialog.


graphics/newterm.gif

You'll also notice that the box under the Custom Binding Expression radio button is automatically populated . This denotes the actual syntax that is placed within a data binding expression in the HTML page (which you can also edit directly by clicking on the HTML tab in the designer). So, for Figure 16.4, the tag for the TextBox would look as follows :

 <asp:textbox id=txtAddress runat="server"   Text='<%# DataBinder.Eval(CustomerDs1,   "Tables[Customers].DefaultView.[0].Address") %>'> </asp:textbox> 

The data binding expression is wrapped in the <%# %> tags and is evaluated during the page processing on the server. In this case, given a data source, the shared Eval method of the DataBinder class is used to evaluate the data binding expression and optionally format the results as a String . For example, you can use the overloaded version of the Eval method to format the Price column into currency using a format string like so:

 <%# DataBinder.Eval(CustomerDs1,   "Tables[Titles].DefaultView.[0].Price", "{0:c} ") %> 

Although the DataBinder class makes formatting simpler, it does so at a cost because it uses late binding. A more efficient technique when using single-value binding is simply to bind directly to the data item and convert it yourself, as in this snippet, where dr is a page-level variable that references the current DataRow to bind to:

 <%# Format(dr("Price"),"currency") %> 

Alternatively, you can do the binding programmatically by handling the DataBinding event at either the control or the page level. For example, the following event handler can be added to the page to handle the DataBinding event for the TextBox that displays the Price :

 Private Sub txtPrice_DataBinding(ByVal sender As Object, _   ByVal e As System.EventArgs) Handles txtPrice.DataBinding    txtPrice.Text = Format(dr("Price"),"currency") End Sub 

To set up the binding for the entire page, you can also handle the DataBinding event at the Page level. When the page is processed by ASP.NET, if it encounters a call to the DataBind method of a control, the page will evaluate any data binding expression for the control and any child controls in the HTML page, and fire the DataBinding event for the control and its children. Because the Page class is derived from Control , this applies to the page as a whole as well. In other words, in Web Forms data binding, you must explicitly call the DataBind method of individual controls or the page in order to instruct it to evaluate the data-binding expressions and fire the DataBinding events. Simply calling DataBind on the page will cascade the binding throughout the page.

Tip

Typically, using the DataBinding events is easier than editing the HTML or using the DataBindings dialog because the syntax is simpler and you have full access to IntelliSense.


Typically, you would call the DataBind event in the Load event of the page, as shown in Listing 2.2 on Day 2.

Multi-Record Binding
graphics/newterm.gif

Multi-record binding is very similar to the complex binding in Windows Forms in that controls that can bind to multiple records expose DataSource and DataMember properties that can be used to bind to a DataSet , DataTable , or DataView . These controls include DropDownList , ListBox , DataGrid , DataList , Repeater , CheckBoxList , and RadioButtonList . Of those controls, only the DataGrid and DataList also expose the DataKeyField property that can be used to specify the primary key field and populate the DataKeys collection so that the key field needn't be displayed in the control.

In addition, the ListBox , DropDownList , RadioButtonList , and CheckBoxList controls all expose DataValueField , DataTextField and DataTextFormat properties.

DataValueField and DataTextField are analogous to the ValueMember and DisplayMember properties of Windows Forms controls, and DataTextFormat is used to apply formatting to the value that is displayed.

Because we looked at binding to the more sophisticated DataGrid control on Day 2, we won't look at more examples here. However, suffice it to say that the DataGrid , along with the DataList and Repeater controls, is a template-based control. A template-based control contains collection templates, each of which can contain child controls that display data in different sections of the control or when the control is in various states. On Day 2, you saw how the EditItemTemplate could be used to display controls when a row in the DataGrid is in edit mode. The template-based controls also expose differing sets of templates, some of which have the same name but are used differently by each control.

Basically, the DataGrid displays the data in a tabular format, whereas the DataList can be used for more flexible formats. The Repeater is like the DataList in that it is flexible but offers no design-time capabilities. Refer to the online documentation for additional examples of using these controls.

Note

Data binding expressions inside templated controls use the Container object as a generic way to refer to the data source and row that is being evaluated. Within the Container , they use the DataItem property to reference the column in the row. This is often used in conjunction with the DataBinder.Eval method, as in DataBinder.Eval(Container.DataItem, "Name") .


Another typical use of multi-record data binding in a Web Form is to display lookup data in a DropDownList control, as shown in Listing 16.6.

Listing 16.6 Multi-record binding. This listing shows a method used on an ASP.NET page to bind a data reader to a DropDownList control.
 Private Sub _loadControls()   ' Load the Publishers drop down   Dim dr As IDataReader   Try     dr = compData.GetPublishersReader()     With dlPublishers       .DataSource = dr       .DataTextField = "Name"       .DataValueField = "PubCode"       .DataBind()     End With   Catch ex As Exception     Throw New Exception("Could not get publisher data", ex)   Finally     dr.Close()   End Try End Sub 
graphics/analysis.gif

As you can see in Listing 16.6, the private _loadControls method is called from the Load event of the page and is responsible for getting a data reader and binding it to the dlPublishers DropDownList control. The method executes the GetPublishersReader method of a data access class referenced by the compData variable to return a data reader that is bound to the control using the DataSource , DataTextField , and DataValueField properties. When the DataBind method is called, the rows are retrieved from the data reader and are rendered by the control.

The interesting aspect of Listing 16.6 is that the dr variable is of type IDataReader , so it can be used with data readers from various providers. Additionally, the data reader returned is ostensibly opened using the CloseConnection command behavior so that when the data reader is closed in the Finally block, the underlying database connection is also closed or returned to the connection pool.

You might be thinking that the technique shown in Listing 16.6 would be a perfect place to use the capability of data readers to return multiple result sets. By doing so, you could encapsulate all the SELECT statements that return read-only data into a single SQL Server stored procedure and then use the NextResult method between the With blocks to bind each control to a result set. Although this does work, unfortunately , it can't be used in conjunction with the CloseConnection command behavior. Specifying this behavior causes the connection to be closed after the first control's DataBind method is called, and therefore results in an exception when the NextResult method is executed. This behavior is particular to SQL Server using both the SqlClient and OleDb providers. As a result, you would need to explicitly create the connection and command objects in the presentation services code or expose a method in the data access class to close the connection.

Mobile Control Binding

If you download and install the Microsoft Mobile Internet Toolkit (MMIT) from MSDN, you can also build Mobile Forms that are targeted for a wide variety of mobile devices such as Web-enabled phones (WAP phones) and Pocket PCs. Interestingly, MMIT includes its own set of Mobile Controls, some of which also support data binding. For example, it includes the List control, which is a template-based control that takes the place of the DataList and Repeater controls; the ObjectList control, which is also templated and used in place of the DataGrid ; and the SelectionList control, which takes the place of the CheckBoxList , DropDownList , ListBox , and RadioButtonList by setting its SelectType property accordingly .

The ability to create multiple user interfaces targeted to different devices in the presentation services tier makes it all the more important to abstract the data and business services into separate tiers to get the maximum reuse possible.

Storing Object State

Because the nature of the Web ”and thus the programming model exposed in a Web Form ”is stateless, any page-level objects (such as a DataSet , DataTable , or DataView ) you create will be destroyed with each new request to the Web server. As you saw on Day 2, when using ADO.NET, this necessitates reretrieving and rebinding the data, as well as perhaps repositioning list-based controls such as the DataGrid and DataList . This is done in the Load event of the page and obviously incurs a roundtrip to the data store each time the page is posted (even when using custom paging), which in Web Forms might be frequent, especially if you handle lots of events on the server.

To minimize the roundtrips to the server, there are two strategies you can use to store the object used as the data source for binding on the Web server. These include using the Session object and using view state.

Note

The two techniques discussed here are useful if you need to store data particular to a user. However, some read-only data might be able to be used by multiple users. In these scenarios, you could cache the data in the HttpApplicationState object (exposed through the Application property of the HttpContext object) or by using the Cache object. The advantage to the Cache object is that the items placed in the cache can have an associated absolute or sliding expiration policy so that you can be notified and refresh the data accordingly.


Session State

Just as in ASP, ASP.NET applications can take advantage of the ability to store data between browser requests in name-value pairs within an object managed by the Web server. In ASP.NET, this is an HttpSessionState object referenced through the Session property of the Page itself and through the HttpContext object.

Note

The HttpContext object is an object that flows throughout a request in ASP.NET and encapsulates all the HTTP-specific information about the request, including references to the Server , Request , and Response objects, in addition to the Session , Application , and other objects the runtime uses to implement features such as tracing and caching. The HttpContext object is accessible through the Context property of the Page class, and thus the HttpSessionState can also be referenced through Context as in Me.Context.Session . See Chapter 10 of my book Building Distributed Applications with Visual Basic .NET (published by Sams) for more information on the ASP.NET runtime and processing model.


Note

As in ASP, the Global.asax file in ASP.NET includes Session_OnStart and Session_OnEnd methods to intercept the Start and End events associated with a user's session. You can use the OnStart event to preload and cache some information that you know a user will need.


This mechanism enables you to place DataSet objects, for example, in session state rather than having to repopulate them from a data store. For example, using session state, the Load event of a page that populates two tables in DataSet might look like that shown in Listing 16.7.

Listing 16.7 Using session state. This listing shows the Load event of a page using session state information.
 Private Sub Page_Load(ByVal sender As System.Object, _   ByVal e As System.EventArgs) Handles MyBase.Load   If Not Page.IsPostBack Then     ' Fill the DataSet with titles from a particular publisher     dsTitles = compData.GetTitles(Me.Request.Form("PubCode"))     Me.Session("dsTitles") = dsTitles   Else     dsTitles = CType(Me.Session("dsTitles"), DataSet)   End If   ' Bind the Data   DataGrid1.DataSource = dsTitles   DataGrid1.DataBind() End Sub 
graphics/analysis.gif

In Listing 16.7, you'll notice that if the page has been reposted to the server, the data will have already been queried. Thus, it can be safely retrieved from the HttpSessionState object and placed in a page-level variable that other methods in the page will utilize. If this is the first request, the data is queried from the data store using the GetTitles method of a data access class, the DataSet saved in session state. In either case, the DataSet is then bound to the DataGrid control to display the data.

Tip

As with classic ASP tracking, session state requires overhead, so if a particular page won't be accessing the Session object, you should set the EnableSessionState attribute of the Page directive at the top of the HTML to False . You can also turn off session state for the entire site by setting the mode attribute of the sessionState element to Off in the configuration file Web.config.


In ASP, it wasn't recommended to store data in the Session object because its implementation had two significant weaknesses:

  • The 120-bit SessionID used to identify the session was always stored as a cookie on the browser. Therefore, if the security policy of a user's employer didn't allow cookies, the Session object couldn't be populated.

  • The data associated with the session and accessed through the SessionID was stored in process on the Web server that initiated the session. As a result, the session data couldn't be shared in a Web farm scenario in which multiple Web servers are processing requests from multiple clients . Although programmatic techniques and system software such as the Windows 2000 Network Load Balancing (NLB) service can be configured to force a client to access the same Web server for each request (referred to as sticky IP ), the overhead and possible imbalance that server affinity creates reduces scalability.

Fortunately, the ASP.NET session implementation addresses both of these weaknesses.

By default, sessions in ASP.NET are configured in the same way as classic ASP; that is, an in-memory cookie is sent to the browser that contains the SessionID ; the session data itself is stored in the memory of the server that initiated the session, and the session timeout is set to 20 minutes. However, the manner and storage attributes for session data can also be configured in the Web.config file within the ASP.NET application. For example, to use cookieless sessions, in which ASP.NET no longer sends a cookie but includes the SessionID in the query string of each request, you simply set the cookieless attribute of the sessionState tag to true as follows:

 <sessionState mode="InProc" cookieless="true" timeout="20" /> 

When the page is processed, it then extracts the SessionID from the query string and associates the user request with the appropriate session. In this way, cookies are not required.

Using a cookieless session has no impact on where the session data is stored, only on how it is accessed. However, ASP.NET includes two options for storing the session data outside the Web server.

SQL Server Storage

The first option is to store the session data in a SQL Server database. This can be done by setting the mode attribute of the sessionState element in Web.config to "SqlServer" . When this is set, the ASP.NET runtime stores session data in a SQL Server database called ASPState on the SQL Server pointed at by the sqlConnectionString attribute. This attribute should contain the data source and security credentials necessary to log on to the server like so:

 <sessionState mode="SQLServer"     sqlConnectionString="server=ssosa;uid=aspSession;pwd=@#r6t;     trusted_connection=yes;pooling=true"     cookieless="false"     timeout="20" /> 

When configured, the application should run identically to when the session data is stored in-process on the Web server. However, keep in mind that all the objects in the session's collection will be serialized at the end of each Web request and transported over the network and saved in the SQL Server database. On each request, the data is read from the database and deserialized into the appropriate objects. This implies that all objects saved in the Session object's collections must be able to be serialized and deserialized by being marked with the Serializable attribute, or additionally derived from MarshalByValueComponent , or have implemented the ISerializable interface.

Obviously, storing session state in the database is a tradeoff between scalability and reliability over performance in the following ways:

  • Session data stored in SQL Server increases the amount of network traffic and database connections generated by the application.

  • Session data decoupled from the Web server can be easily shared across servers in a Web farm, thereby increasing scalability.

  • Session data stored on a separate machine isn't lost when the application crashes or is restarted.

  • Session data stored separately from the Web server doesn't impact the memory requirements of the Web server as does in-process storage.

If none of the previous considerations are relevant to your application, use the in-process setting because it performs better.

State Server
graphics/newterm.gif

In addition to storing session data in a SQL Server, ASP.NET also provides for storing data in a separate in-memory cache controlled by a Windows service. The service is called the ASP.NET State service ( aspnet_state.exe ) and can be run on either the same machine as the Web server or a separate machine. To use the service, the mode attribute of the sessionState element in Web.config is set to "StateServer" , and the stateConnectionString attribute must include the server and port used to connect to the service like so:

 <sessionState mode="StateServer" stateConnectionString="tcpip=ssosa:42424"     cookieless="false" timeout="20" /> 

In this case, the state service is running on a machine called "ssosa" at the port 42424, which is the default. The port can be configured at the server by modifying the Port value in the aspnet_state registry key under the HKLM\SYSTEM\CurrentControlSet\Services .

Obviously, using the state service has the same advantage of process isolation and sharability across a Web farm. However, if the state service is stopped , all session data is lost. In other words, the state service doesn't persistently store the data as does SQL Server; it simply holds it in memory.

View State

The ASP.NET programming model supports the concept of view state where information about the state of a Web Form is embedded in the HTML page sent to the browser. This information is used by the ASP.NET runtime to populate the properties of the controls on the page and the page itself when the form is posted back to the server. The view state is represented in the hidden __VIEWSTATE control on the page in the browser and the ViewState property of the Page object.

To add custom information such as a DataSet to the ViewState , you can programmatically manipulate the underlying StateBag object exposed by the ViewState property. The StateBag class simply exposes a collection of StateItem objects by implementing the ICollection , IDictionary , and IEnumerable interfaces. You can add items to the StateBag of a page by calling the Add method and providing the key and the value as arguments. For example, as shown in Listing 16.8, you could use add a DataSet to the ViewState in the same way that you could use the HttpSessionState object.

Listing 16.8 Using view state. This listing shows the Load event of a page using view state information.
 Private Sub Page_Load(ByVal sender As System.Object, _   ByVal e As System.EventArgs) Handles MyBase.Load   If Not Page.IsPostBack Then     ' Fill the DataSet with titles from a particular publisher     dsTitles = compData.GetTitles(Me.Request.Form("PubCode"))     Me.ViewState.Add("dsTitles") = dsTitles   Else     dsTitles = CType(Me.ViewState("dsTitles"),DataSet)   End If   ' Bind the Data   DataGrid1.DataSource = dsTitles   DataGrid1.DataBind() End Sub 

Using the view state in this way has two advantages over session state. Particularly, there is less overhead on the server because the objects aren't persisted anywhere and simply travel with the form. In addition, view state promotes information hiding because only this particular Web Form needs to see these values. However, the flip side is that an object stored in view state is accessible only in the particular page in which it's created. If the object must be accessible across pages, you'll need to use session state. Also, because view state is represented as a binary string embedded in the page sent to the browser, the larger the object you store in view state, the more bandwidth it takes to move the object back and forth between the browser and Web server. For this reason, you should consider using view state only if the DataSet or DataTable contains a limited number of rows.

Validating Controls

As with Windows Forms controls, you also need to be able to validate user input in a Web Form. To make this process simple, ASP.NET includes controls derived from BaseValidator , as shown in Table 16.1.

Table 16.1. Web Forms validation controls. The controls listed here all derive from BaseValidator .
Control Description
CompareValidator Used to compare the contents of the control with a constant or another control
CustomValidator Used to validate the contents of the control based on custom logic
RangeValidator Used to ensure that the control's value is between a lower and upper limit
RegularExpressionValidator Used to validate a control based on a regular expression
RequiredFieldValidator Used to ensure that the control has a value
ValidationSummary Used to display the error messages from all the validation controls on the page

As shown in Table 16.1, the six validation controls handle everything from making sure that a control is populated to handling custom validation code running on the server. In total, these controls offer a level of functionality that must be custom coded in Windows Forms. Each instance of one of these controls, with the exception of the ValidationSummary control, can be used to validate one control on the form. To validate multiple controls, you need to add multiple instances of the validator controls to the page as well. After you do so, the HTML code in the page for a single control might look like the following code snippet:

 <asp:RequiredFieldValidator id=LNameValidator    ControlToValidate="txtLName" Display=Dynamic    CssClass="body-copy" runat="server"    ErrorMessage="Last Name is required" Text="*" > </asp:RequiredFieldValidator> 

In this case, the RequiredFieldValidator is used to make sure that the txtLName control on the form contains a value (as indicated by the ControlToValidate property). You might also use a RegularExpressionValidator control to make sure that an e-mail address is entered in the appropriate format, like so:

 <asp:RegularExpressionValidator   id="EmailAtValidator" runat="server"   ErrorMessage="Email Address must contain @"   ValidationExpression="(.)+(@)+(.)+"   Display=Static Text="*" CssClass="body-copy"   ControlToValidate="txtEmail"> </asp:RegularExpressionValidator> 

Note

Of course, as with other controls, you can programmatically manipulate the properties of validation controls in the code for the page as well.


Here, the RegularExpressionValidator is used to ensure that the e-mail address contains an "@". Note that the ValidationExpression property is populated with a regular expression where the expression ensures that at least one character (.)+ precedes the "@" symbol (@) followed by at least one more character (.)+ .

Note

In the case where a single control is the target of two validation controls, there is an order of precedence to how they are fired . As you might expect, the RequiredFieldValidator is fired first, followed by the RegularExpressionValidator .


Finally, you can also place a ValidationSummmary control on the page that enables you to display all the error messages in a central location. In this way, the messages can be grouped so that users don't have to scan the page searching for error messages. A ValidationSummary control on the page would be rendered as follows:

 <asp:ValidationSummary id=ValidationSummary     runat="server" ShowMessageBox=True CssClass="body-copy"     DisplayMode= BulletList HeaderText="Errors occurred."> </asp:ValidationSummary> 

Note that the DisplayMode property is set to BulletList to indicate that the errors display in a list of bulleted items directly beneath the HeaderText . The ShowMessageBox property takes effect when the validation is done on the client and displays a message box with all the errors in addition to printing them to the validation summary control. In addition, error messages print out in red by default. This can be changed by setting the properties of the control (such as ForeColor ) or using a Cascading Style Sheet (CSS). In this case, the CSSClass property is set to "body-copy" , which sets the font according to the style sheet linked in the LINK tag at the top of the page.

By default, the validation controls perform the validation on the client if the browser supports DHTML by rendering JavaScript code in the HTML page. This is the default so that server roundtrips are reduced and makes the application more responsive . To force validation to occur on the server for individual controls, you can set the EnableClientScript property of the control to False , whereas for the entire page, you can set the ClientTarget attribute of the Page directive to " downlevel ".

Note

Validation can be disabled on the server by setting the Enabled property of the validation control to False . If validation must be disabled from client-side script, you can set the Page_ValidationActive global variable to False . This variable is included on pages that use client validation through a JavaScript file ( WebUIValidation.js ) included with the page.


You'll also notice in the previous code snippets that both the ErrorMessage and Text properties are set. Typically, you'd only set the ErrorMessage property, but because the page includes a ValidationSummary control, the Text property specifies the message that will be displayed at the location of the validation control, whereas the ErrorMessage is displayed in the ValidationSummary control. In this way, you can provide a visual cue to the user as to which fields were in error, much like the ErrorProvider control, and still group all the error messages in one place.

When the validation controls use client-side validation and all the validation passes , the form is posted back to the server. However, if the validation controls actually perform their validation on the server, the validation occurs before the server event that initiated the postback occurs. Rather than taking any special action (other than error reporting) when errors are encountered , the validation controls simply set the IsValid property of the individual controls and the Page object to False . As a result, code on the server must check for this value before proceeding. Not checking this property results in errors reported to the client but normal processing to otherwise continue.

Customizing Validation

Although the RegularExpressionValidator control is especially flexible, you have the option of customizing the validation process. You can accomplish this on the server by adding a CustomValidator control to the page and setting its ControlToValidate property to the appropriate control. Then, within the page class, you can create a method to handle the ServerValidate event of the control.

This method then performs the validation by referring to the value argument that contains the value of the control being validated . Returning True from this function means that the validation was successful. This technique can be used, for example, to dynamically validate the control against values read from a database.

An analogous technique can be used to perform custom validation on the client by populating the ClientValidationFunction property with the name of a client-side function to execute.

for RuBoard


Sams Teach Yourself Ado. Net in 21 Days
Sams Teach Yourself ADO.NET in 21 Days
ISBN: 0672323869
EAN: 2147483647
Year: 2002
Pages: 158
Authors: Dan Fox

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