Data Binding - The Concepts


Data Binding “ The Concepts

The exact meaning of data binding can be quite difficult to pin down. In programming languages such as Visual Basic and applications such as Microsoft Access, the term data binding describes the way that values from a collection of data, such as a recordset, are connected to controls on a form. As the form is used to navigate through the records, the values of each of the columns are automatically displayed in the controls. The controls are bound to the columns in the recordset, and you don't have to write any code to display the values or update the original data source.

However, the disconnected nature of the HTTP protocol means that the traditional client/server data binding used in Visual Basic and Access cannot be used over an HTTP-based network connection. When Internet Explorer 4 appeared, it included some clever client-side and server-side COM components that allowed a similar technique to be used over HTTP. This was referred to as client-side data binding , and worked well. However, the browser-specific requirements of this technology, combined with suspicions about security that it raised, meant that it didn't really catch on in a big way.

Doing It All on the Server

The continuing diversification of client devices means that any browser-specific technology is unlikely to have long-term appeal . Accordingly , the .NET Framework vision is to provide support for all types of client. Ultimately, this means either you have to build applications that detect the client device type and change their behavior accordingly, or implement all the functionality on the server.

In many cases doing it all on the server is a good plan, as it allows you to exert control over output and security within your applications. Developments in server and web farm technologies make it much easier to provide scalable and reliable sites, and ASP.NET is designed to create fast responses to client requests through pre-compilation and caching.

So how does this relate to the topics of this chapter? The answer is that in .NET you move towards the concept of server-side data binding . You can take advantage of the time saving and code saving features of data binding “ just as you would with Visual Basic and Access “ but use it across HTTP in a disconnected environment like the Web.

With data binding in ASP.NET, you simply tell the controls or the page where to find the data. It extracts the values and builds the page with this data in it as seen in the next section.

Displaying Data “ ASP versus ASP.NET

With ASP 3.0 and earlier, you could use components or a technology such as ADO to create a Recordset object that contains rows of data for display. To get them into the page, you would usually iterate through the rows “ extracting values, formatting them, and inserting them into the output as follows :

  ...' assuming we've got a Recordset object containing the data ...   Response.Write "<table>"   Response.Write "<tr><th>Date</th>"   Response.Write "<th>Subject</th>"   Response.Write "<th>User Name</th>"   Response.Write "<th>Content</th></tr>"   Do While Not objRecs.EOF   strDate = FormatDateTime(objRecs("dtDate").value, vbLongDate)   Response.Write "<tr><td>" & strDate & "</td>"   Response.Write "<td>" & objRecs("tSubject").value & "</td>"   Response.Write "<td>" & objRecs("tUserName").value & "</td>"   Response.Write "<td>" & objRecs("tContent").value & "</td></tr>"   objRecs.MoveNext   Loop   Response.Write "</table>"   objRecs.Close  

You had to do all this just to get a simple unformatted table containing values from the rows in the recordset. In ASP.NET you can do the same in only two lines of code by using a server control:

  <!-- the server control located in the HTML section of the page -->   <ASP:DataGrid id="MyDataGrid" runat="server" />   ...' assuming we've got a DataView object containing the data ...   MyDataGrid.DataSource = objDataView   MyDataGrid.DataBind()  
Note

Data access objects such as DataView are covered in detail in the Chapters 8 to 10.

The server control does much the same as the ASP 3.0 code you saw. It automatically creates an HTML table with the column names in the first row, followed by a series of rows that contain the values from each of the source data rows. What's more, you can now change the appearance of the table by just setting a few properties of the ASP:DataGrid control. You can add:

  • Automatic sorting with only a two-line subroutine.

  • Automatic paging, with each page showing the number of rows required and with links to the other pages, by just setting one property and creating two lines of code.

And this only scratches the surface. This control can be used in ways that will cater for almost any dataset presentation requirement. What's more, there are several other controls that are designed to display repeated data such as this, and even more that work with a single item of data at a time through server-side data binding.

Data Binding Syntax

Data binding was used in a couple of the examples in Chapters 5 and 6, but was not discussed in depth. Let's concentrate on the theory here, and then look at how to use the new ASP.NET server controls to really get the benefits of server-side data binding.

The principle behind server-side data binding is to get ASP.NET to insert one or more values from a data source into the page, or into a control on the page. The basic syntax uses a construct that looks like a server-side script block, with a # character as an indicator that this is actually a data-binding statement:

  <%#  name-of-data-source  %>  

Code to be executed cannot be placed within this block, as although it looks like a server-side script block, it isn't. Only specific data-binding syntax expressions can be used within the block.

There are two basic scenarios in which you would want to bind a control:

  • Single-value data binding :When you have a single value to bind to a control. For example, you might want to set one of the properties (or attributes) of that control. In this case, the bound value is often used to set the displayed content of the control (the Text or Value property), and is suited to controls that only display a single value, such as the <input> , ASP:TextBox , and ASP:Hyperlink controls.

  • Repeated-value data binding :When the data source contains more than one value. For example, you might want to bind a list, a collection, or a rowset to a control that can display more than one value. Examples include the various types of list controls such as <select> , ASP:ListBox , and ASP:CheckBoxList .

Although the techniques for both these types of binding are fundamentally similar let's examine the concepts of each separately.

Single-Value Data Binding

When you bind controls to single values such as properties, methods , or expressions, you use one of the following simple types of syntax:

  <%# property-name %>  

Or: Or:

  <%# expression %>  

This shows there are several possible sources for the value that will be bound to the control, and let's look at these next.

  <%# method-name(parameter, parameter, ...) %>  

Sources of Data for Single-Value Binding

The source of the value that can be used with single-value data binding includes:

  • The value of a property declared in either the page, or in another control or object.

  • The result returned from a method declared in either the page or in another control or object.

  • The result of evaluating an expression.

All of these must return a single value that can be bound to a control or placed directly within a page. For example, you can declare a property named ImageURL within the code of the page as follows:

  ReadOnly Property ImageURL() As String   Get   'read-only property for the Page   Dim strURL As String   'some code would be here to calculate the value   'we just set it to a fixed value for illustration   strURL = "myimage.gif"   Return strURL   End Get   End Property  

Then insert the value directly into the page itself, or as the value of an attribute for a control, using:

  <%# ImageURL %>  

The only remaining task is to activate the binding when the page is loaded. This is done using the DataBind method (we'll look at this in detail shortly):

  Sub Page_Load()   DataBind()   End Sub  

Using Controls with Bound Values

The real advantage in using bound values is that the data binding statement block can be used within other controls, and the value of one control can come from another control. For example, you can link a label to a textbox by specifying the Text property of the TextBox control as the Text property of the Label control.

Now, each time the page is submitted, the value in the Label control named MyLabel will be the value that was present in the TextBox control named MyTextBox “ and to accomplish this you don't need to write any code other than to call the DataBind method:

  <form runat="server">   <ASP:TextBox id="MyTextBox" runat="server" />   <ASP:Label id="MyLabel" Text="<%# MyTextBox.Text %>" runat="server" />   <input type="submit" />   </form>   <script language="VB" runat="server">   Sub Page_Load()   DataBind()   End Sub   </script>  

This technique isn't limited to just setting the Text property of a control. You can use it to insert a value into almost any control.

For example, to specify the Src property of an ASP:Image control you could use:

  <ASP:Image src="<%# ImageURL %>" ImageAlign="middle" runat="server" />  

To specify the text caption of an ASP:CheckBox control you could use:

  <ASP:CheckBox Text="<%# ImageURL %>" runat="server" />  

To specify the text and target URL for an ASP:Hyperlink control you could use:

  <ASP:Hyperlink Text="<%# ImageURL %>" NavigateUrl="<%# ImageURL %>"   runat="server" />  

This technique works in the same way for HTML controls and elements that aren't actually server controls.

To specify the text that appears in an HTML text control element, you would use:

  <input type="text" value="<%# ImageURL %>" />  

To specify the caption of an HTML submit button, you would use:

  <input type="submit" value="<%# ImageURL %>" />  

Or to specify the target URL and hotlink text in an HTML <a> element, you would use:

  <a href="<%# ImageURL %>"><%# ImageURL %></a>  

If required, you can concatenate explicit values with the bound value. For example, it can be used to specify just the file name part of a complete URL:

  <a href="http://mysite.com/images/<%# ImageURL %>">   View the file named '<%# ImageURL %>'</a>  

Activating the Binding

As noted earlier, once you've specified the data binding statement blocks in a page, you must activate the binding when some other event occurs (usually when the page is loaded) to get the appropriate values inserted. If you don't, the ASP engine ignores the data binding blocks when the page is compiled, and they won't be replaced by the intended value. The binding process is activated using the DataBind method, which is available at several places within the hierarchy of the page:

  • To bind all the controls on the page, call the DataBind method of the Page object (as Page is the default object, Page.DataBind or just DataBind can be used as done in the examples so far). This is the only way to activate the binding for controls that are not specifically designed for use with data binding. It also binds any values that are inserted directly into a page, rather than into a control of some kind.

  • To bind just a single control, call the DataBind method of that control. This only applies to those list controls that are designed specifically for use with data binding.

  • To bind just one row or item object from the data source within a control, call the DataBind method of that object. Again, this only applies to list controls that are designed specifically for use with data binding.

A Single-Value Data Binding Example

Figure 7-2 shows a Simple Single-Value Data Binding (provided in the code download as simple-single-binding.aspx ) sample page. It shows how single-value data binding can be used with a whole range of controls.

click to expand
Figure 7-2:
Note

You can click on the [view source] link at the bottom of the page to see the complete sourcecode for the page. It uses the code you saw earlier to expose a simple ImageURL property.

Each of the controls in the page then uses the ImageURL property value to set one or more of their properties. Finally, the code in the Page_Load event handler calls the DataBind method of the Page object to bind all the controls on the page to the property value:

  Sub Page_Load()   Page.DataBind() 'bind all the controls on the page   End Sub  

We've also provided a similar example page that binds to the result of a method rather than a property value. This page, Single-Value Data Binding to a Method Result ( method-single-binding.aspx ) looks identical to the previous example when it's displayed in a browser. However, it differs in its definition of a method named ImageURL , which returns the value "myimage.gif" :

  Function ImageURL() As String   Return "myimage.gif"   End Function  

The only other difference is that now the expressions in the data binding blocks include parentheses, because the data source is a method (although in Visual Basic it works just as well without them):

  <ASP:Label Text="<%# ImageURL() %>" runat="server" />  

Repeated-Value Data Binding

Single-value data binding is a useful technique, but data binding becomes a lot more valuable when there are repeating sets of values to display “ for example, a rowset from a relational database, or an array of values.

ASP.NET provides eight list controls that are designed to work with repeated-value data binding. They have a set of properties and methods that allow them to be connected to a data source. Then, they automatically create a display row or display item for each row or item in the data source. For example, a <select> list control will automatically create an appropriate set of <option> elements to display all the rows or items in the data source.

One obvious advantage with these controls is that you don't have to provide any of the HTML elements or other content. The control does it all automatically (although you can add HTML elements to the output to customize it if required).

The List Controls Designed for Repeated Binding

The eight controls specifically designed for use with server-side data binding are:

  • The HTML <select> element, implemented by the System.Web.UI.HtmlControls.HtmlSelect .NET class. When presented with a suitable source of repeating data values it creates a standard HTML <select> list with repeating <option> elements.

  • The ASP:ListBox control, implemented by the System.Web.UI.WebControls.ListBox .NET class. This control also creates a standard HTML <select> list with repeating <option> elements. By default, it creates a list-box rather than a drop-down list like the <select> element, though the appearance of both can be changed by setting the number of items to display.

  • The ASP:DropDownList control, implemented by the System.Web.UI.WebControls.DropDownList .NET class. Again, this control creates a standard HTML <select> list with repeating <option> elements. However, by default, it creates a drop-down list rather than a listbox.

  • The ASP:CheckBoxList control, implemented by the System.Web.UI.WebControls.CheckBoxList .NET class. This control creates a list of standard HTML <input type="checkbox"> elements “ one for each row or item in the data source.

  • The ASP:RadioButtonList control, implemented by the System.Web.UI.WebControls.RadioButtonList .NET class. This control creates a list of standard HTML <input type="radio"> elements “ one for each row or item in the data source. It also sets the HTML name attribute (represented by the GroupName property of the control) to the same value so that the radio buttons in the list are associated.

  • The ASP:Repeater control, implemented by the System.Web.UI.WebControls.Repeater .NET class. By default, this control generates no visible interface or formatting and no HTML content. It simply repeats the content defined within the control once for each row or item in the data source.

  • The ASP:DataList control, implemented by the System.Web.UI.WebControls.DataList .NET class. This control repeats the content defined within the control once for each row or item in the data source, either enclosing each item in an HTML table row, or delimiting the items using an HTML <br /> element to create a list. It can also lay the content out in more than one column, and process items vertically or horizontally within the columns.

  • The ASP:DataGrid control, implemented by the System.Web.UI.WebControls.DataGrid .NET class. This is a fully featured grid control designed for use with data contained in a DataView , DataSet , or DataReader object, or a collection. It generates a visible interface by way of an HTML table, automatically adding the column or item names to the header row. There are also many other useful features built in to make it easy to customize the display (which will be discussed later on).

Figure 7-3 (taken from the example page you'll see shortly) shows the physical appearance of these controls:

click to expand
Figure 7-3:
The Properties of a Repeated Binding Control

All the controls designed for use with server-side data binding expose properties and methods that are used to manage the binding. The properties are shown as follows:

Property

Description

DataTextField

Specifies which field or column in the data source contains the values to be used for display. For example, the values used as the text for <option> elements in a listbox, or the captions of the checkboxes in a CheckBoxList control.

DataValueField

Specifies which field or column in the data source contains the values to be used as the Value property of the control elements. For example, the values used as the value attribute for <option> elements in a listbox.

DataTextFormatString

The format string to be used for the values from the column or field specified in the DataTextField property when displaying these values in the control. For example, "{0:C}" for formatting currency values, or "{0:dddd MMMM dd yyyy} " for formatting dates.

DataMember

Specifies the set of rows to bind to when the data source contains more than one rowset. For example, the name of the table when binding to a DataSet object.

Many other properties are specific to individual controls, and govern how the content is displayed. You'll look at most of these in some example pages that use the controls later in this chapter.

The Methods of a Repeated-Value Binding Control

All of the controls designed for use with repeated-value data binding expose the two methods shown in the following table for working with bound data:

Method

Description

DataBind

Causes the control to populate itself with the data from the data source “ in effect activating the bindings that are specified within the declaration of the control.

FindControl

Used to get a reference to a child control within the container (that is, within the bound control). This is useful when you want to check the value in another child control (such as a table cell ) within the same row as the current control. It is normally used within event handlers that are executed once for each row or item “ for example, the DataBinding event.

The Events of a Repeated-Value Binding Control

There is a wide range of events raised by the list controls, of which many are specific to the control type. However, there are two that are common across all list controls designed for use with data binding, as shown in the following table:

Event

Description

DataBinding

Occurs for each row or item in the data source as that row or item is created within the control during the execution of the DataBind method. The row or item is passed to the event within the event parameters, and code can examine and modify the content of that row or item as the container control is populated .

SelectedIndexChanged

Occurs when the currently selected item changes and the page is posted back to the server. It allows code to change the display to reflect the user's selection.

Sources of Data for Repeated-Value Binding

So, having looked at the controls, the next question is what kind of data source can you bind to them? In technical terms, the list controls can be bound to any data source that implements the IEnumerable , ICollection , or IListSource interface. In practical terms, the list controls can be bound to:

  • A Collection , such as the collection of values in Request.Form , the collection of tables in a DataSet object's Tables collection, or a collection you create and populate.

  • An ArrayList , which contains a simple list of values. This is a good way to create a list of items for display in such as a listbox.

  • A HashTable , which contains items that are identified by a key, rather like a Dictionary object. Each item has a Key and a Value property, which makes this type of data source ideal for things like listboxes, in which the text to be displayed and the value to be returned when that item is selected are different.

  • An ADO.NET DataView object, which contains rows from a DataTable that is populated from a database, or is manually created and populated using code (the whole topic of creating and manipulating relational data is discussed in Chapters 8 to 10).

  • An ADO.NET DataSet object, which contains one or more DataTable objects that are populated from a database, or which are manually created and populated using code. This is a disconnected object that is easy to pass between the tiers of an application. The actual table to which the control is bound is specified in the DataMember property of the control.

  • An ADO.NET DataReader object, which provides connected forward-only and read-only access to a database for extracting data. It can expose one or more rows of data, and essentially behaves in the same way as a DataView object for binding. For performance reasons, use a DataReader rather than a DataView or DataSet when possible. We'll explore the scenarios that do require the use of a DataView or DataSet , later in the chapter.

    Note

    Chapter 15 provides a full examination of the various types of collection in the .NET Framework. Chapters 8, 9, and 10 contain a full examination of how to work with relational data and the DataView , DataSet , and DataReader objects.

The Syntax for Repeated-Value Data Binding

To bind controls to single values (properties, methods, or expressions as seen earlier), use the following:

  <%#  name-of-data-source  %>  

However, data sources used for repeated-value binding often have more than one field (that is, more than one value in each row or list item ). Examples include the HashTable , which contains a Key and a Value , and the DataView or DataReader object, where each item is a DataRow object. Here, specify which field or column (that is, which value from each row or list item) you want to bind to the control.

Many of the list controls are also capable of displaying or using more than one value for each item in the list. For example, a <select> element can use one value for the content of an <option> element, and one value for that <option> element's value attribute:

  <select>   <option value="value1">Text1</option>   <option value="value2">Text2</option>   ...   </select>  
Mapping Fields in the Data Source to Control Properties

There are two ways to map (or connect) specific fields in each row of the data source to the properties or attributes of a control; which method to use depends on the type of control you are binding to:

  • If the control supports templates , declaratively create a template that defines the content of each 'row' or item that the control will display.

  • If the control does not support templates, dynamically assign the fields in the data source to the attributes of the control by setting the properties of the control at runtime.

The controls in ASP.NET that do support templates are Repeater , DataList, and DataGrid . So, for one of these controls, you can declare a template within the control element and place the data binding instructions within it. Reference the row or list item as a DataItem object within the control's Container , and specify the field or column that you want to connect to. For example, when binding to a HashTable , specify either the Key property:

  Key: <%# Container.DataItem.Key %>  

Or the Value property:

  Value: <%# Container.DataItem.Value %>  

When binding to a Collection , DataView , or DataReader object, specify the property, field, or column name itself:

  Value from DataView/DataReader: <%# Container.DataItem("BookTitle") %>  

Or:

  Value from Collection: <%# Container.DataItem("ForeColor") %>  

You could, for example, use a Repeater control to display the Key and Value in each row of a HashTable as follows:

  <ASP:Repeater id="MyRepeater" runat="server">   <ItemTemplate>   <%# Container.DataItem.Key %> =   <%# Container.DataItem.Value %><br />   </ItemTemplate>   </ASP:Repeater>  

Then, in your Page_Load event handler, simply assign the data source to the control and call its DataBind method:

  MyRepeater.DataSource = tabValues   MyRepeater.DataBind()  

Mapping Fields Dynamically at Runtime

For controls that don't support templates, you must set the properties (listed earlier) at runtime. These properties specify the field from the data source that will provide the visible output for the control (the DataTextField property) and the field that will provide the non-displayed values for the control (the DataValueField property).

So, using the previous example of a <select> list populated from a HashTable , you could use one 'column' (probably the Key ) as the value attribute of each <option> element, and the other 'column' (the Value ) as the text of the <option> element. Declare the control as follows:

  <select id="MySelectList" runat="server" />  

Then set the properties of the control in the Page_Load event to display the appropriate fields from the data source:

  MySelectList.DataSource = tabValues   MySelectList.DataValueField = "Key"   MySelectList.DataTextField = "Value"   MySelectList.DataBind()  

The DataGrid control is clever enough to be able to figure out fields in the data source automatically, and display all the values. This works when the data source is an Array , a DataView , a DataSet , or a DataReader , but not when the data source is a HashTable .

Note

We'll look at the DataGrid control in detail towards the end of this chapter.

Evaluating Expressions with the Eval Method

The data binding statement block in a control that uses templates (such as the Repeater , DataList , and DataGrid ) can contain instances of only the following expression and derivatives of it.

In its simplest form, this expression is:

  <%# Container.DataItem("  field-name  ") %>  

A common derivative is the use of the Eval method of the DataBinder object to specify a value within a data source (where it contains more than one value per row), and optionally format the value for display. In fact, there are three ways to use the Eval method:

  • When each row or list item in the data source contains more than one value (more than one column or field) “ for example, a row from a DataView based on a database table, or a HashTable object.

  • When you want to use a different object than the one the control is bound to as the source of the value.

  • When you want to format the value for display “ for example, by taking a numeric value and formatting it as currency.

The first of these is just an extension of the syntax used in the previous section, and adds nothing to the process other than a performance hit. In general it should be avoided. Here is an example, however, in which the required value is in the column named BookTitle within a row in a DataView object:

  <%# DataBinder.Eval(Container.DataItem, "BookTitle") %>  

The DataBinder.Eval method uses a technique called late-bound reflection to evaluate the expression. Therefore, it carries a noticeable performance overhead compared to the standard data binding syntax in which just the value name is specified.

Another important point is that you have to include a line continuation character in Visual Basic when using the Eval statement if you need to break the statement over more than one line. It's not really necessary, but should be kept in mind when you are reading published code listings in which the code could wrap to the next line.

The second way to use the Eval method is when you want to bind to an object that is not defined in the DataSource for the control. This allows you to reference specific values in that object, which are then used in every row that is displayed.

For example, if you have a DataView named objCityData that contains information about cities, you can specify the value of the CityName column in the fourth row (rows are indexed from zero) of the DataView with:

  <%# DataBinder.Eval(objCityData, "[3].CityName") %>  

However, the most common and useful application of the Eval method is to format values for display.

The Eval method takes three parameters, the last of which is optional. This third parameter, which we didn't use in the previous examples, is a format string that defines the format of the output.

For example, you can specify that the content of the PublicationDate field in your data source should be displayed in standard date format using:

  <%# DataBinder.Eval(Container.DataItem, "PublicationDate", "{0:D}") %>  

The result from this example is something like " 10 March 2001 " (it depends on the regional settings of the server). When you use the Eval method, you can only have one value in each expression, so the first number in the curly braces (a placeholder for the variable containing the value to be formatted) must always be zero.

The character(s) after the colon (in this case D ) denote the format itself. The common format strings used with numeric values are shown as follows:

Format character

Description

Example (US English culture)

C or c

Currency format

$1,234.60 , ($28.15) , $28.75

D or d

Decimal format

205 , 17534 , -65

E or e

Scientific (exponential) format

3.46E+21 , -1.2e+3 , 3.003E-15

F or f

Fixed-point format

34.300 , -0.230

G or g

General format

Depends on actual value

N or n

Number format

3,456.23 , 12.65 , -1.534

P or p

Percent format

45.6% , -10%

X or x

Hexadecimal format

&H5f76 , 0x4528 (depends on actual value)

The following table shows the specific format strings used with dates:

Format character

Description

Example (US English culture)

d

Short date

M/d/yyyy

D

Long date

dddd , MMMM dd , yyyy

f

Full (long date and short time)

dddd , MMMM dd , yyyy HH:mm aa

F

Full (long date and long time)

dddd , MMMM dd , yyyy HH:mm:ss aa

g

General (short date and short time)

M/d/yyyy HH:mm aa

G

General (short date and long time)

M/d/yyyy HH:mm:ss aa

M or m

Month and day

MMMM dd

R or r

RFC1123 format

ddd , dd MMM yyyy HH':'mm':'ss'GMT'

s

ISO 8601 sortable using local time

yyyy-MM-dd HH:mm:ss

t

Short time

HH:mm aa

T

Long time

HH:mm:ssaa

u

ISO 8601 sortable using universal time

yyyy-MM-ddHH:mm:ss

U

Universal sortable date/time

dddd , MMMMdd , yyyyHH:mm:ss aa

Y or y

Year and month

MMMM , yyyy

It's also possible to use pre-defined characters to create a picture for numeric values. For example, the format string 00#.## , when applied to the number 1.2345 would produce 001.23 . If you want to specify positive, negative, and zero formats, separate each with semi-colons. So given the format string 00#.##;(00#.##);[0] , you would get (001.23) for -1.2345 and [0] for zero. All other characters are copied directly to the output, so the format string My value is: #.00 would, with the number 42, produce My value is: 42.00 . The picture format characters for numbers are shown as follows:

Format character

Description

Displays a zero if there is no significant value “ that is, it adds a zero in front of a number, or at the end of the number after the decimal point.

#

Digit placeholder, replaced only with significant digits. Other occurrences of this symbol are ignored if there is no significant digit.

.

Displays the decimal point character used by the current culture.

,

Separates number groups with the character used by the current culture, such as 1,000 in the US English culture. Can also be used to divide the value of a number “ for example, the format string 0,, will display the number 100,000,000 as just 100 in the US English culture.

%

Displays the percent character used by the current culture.

E+0 , E-0 , e+0 , or e-0

Formats the output as scientific or exponential notation.

\

Displays the following character as a literal “ it is not interpreted as a format character.

" or '

Any characters enclosed in single or double quotes are interpreted as a literal string.

{ and }

Double curly brackets are used to display a single literal curly brace “ for example, {{ displays { and }} displays } .

;

Separates the two or three sections for positive, negative, and zero values in the format string.

Remember that the DataBinder.Eval method carries a noticeable performance overhead compared to the standard data binding syntax of specifying just the value name, and you should use it only when necessary. In particular, avoid it when formatting of the value is not actually required. You can often format values as you extract them from a database, or within the definition of the property or method that provides the bound values.

Simple Repeated-Value Data Binding Examples

We've provided five example pages that are fundamentally similar, but demonstrate the different types of data source you can use with repeated-value data binding. There are examples of binding to an ArrayList , a HashTable , a DataView , a DataSet , and a DataReader . Let's start with the ArrayList example, and then see the differences between this and each of the other examples in turn .

Repeated-Value Binding to an ArrayList Object

The simplest example of repeated-value data binding uses a one-dimensional ArrayList that is created and populated with values in the Page_Load event handler. This example page, Simple Repeated-Value Data Binding ( simple-repeated-binding.aspx ) shown in Figure 7-4 includes one of each of the eight list controls bound to your ArrayList :

click to expand
Figure 7-4:

The HTML section of the page contains the definition of the eight list controls as shown in the following code. You can see that, with the exception of the Repeater and DataList controls, all you do is declare the control itself:

  HTML <b>&lt;select&gt;</b> element:<br />   <select id="MySelectList" runat="server" /><p />     <b>&lt;ASP:DropDownList&gt;</b> control:<br />   <ASP:DropDownList id="MyDropDown" runat="server" /><p />     <b>&lt;ASP:ListBox&gt;</b> control:<br />   <ASP:ListBox id="MyASPList" runat="server" /><p />   <b>&lt;ASP:DataGrid&gt;</b> control:<br />   <ASP:DataGrid id="MyDataGrid" runat="server" /><p />     <b>&lt;ASP:Repeater&gt;</b> control:<br />   <ASP:Repeater id="MyRepeater" runat="server">   <ItemTemplate>   <%# Container.DataItem %>   </ItemTemplate>   </ASP:Repeater><p />   <b>&lt;ASP:DataList&gt;</b> control:<br />   <ASP:DataList id="MyDataList" runat="server">   <ItemTemplate>   <%# Container.DataItem %>   </ItemTemplate>   </ASP:DataList><p />     <b>&lt;ASP:CheckBoxList&gt;</b> control:<br />   <ASP:CheckBoxList id="MyCheckList" runat="server" /><p />     <b>&lt;ASP:RadioButtonList&gt;</b> control:<br />   <ASP:RadioButtonList id="MyRadioList" runat="server" /><p />  

However, the Repeater and DataList controls require that you specify the output required for each repeated item, and so for these an <ItemTemplate> specification is included as well. The content placed inside the <ItemTemplate> is repeated once for every item in the data source. In your code, you're just specifying the DataItem itself “ the value of that item within the ArrayList .

The Page_Load Event Handler

The remainder of the page is the event handler that runs when the page is loaded. It simply creates a new ArrayList and fills it with five string values. Then it sets the DataSource property of each of the eight list controls to this ArrayList and calls the DataBind method of the Page object to bind all the controls:

  Sub Page_Load()     'create an ArrayList of values to bind to   Dim arrValues As New ArrayList(4)   arrValues.Add("Microsoft")   arrValues.Add("Sun")   arrValues.Add("IBM")   arrValues.Add("Compaq")   arrValues.Add("Oracle")     'set the DataSource property of the controls to the array   MySelectList.DataSource = arrValues   MyDropDown.DataSource = arrValues   MyASPList.DataSource = arrValues   MyDataGrid.DataSource = arrValues   MyRepeater.DataSource = arrValues   MyDataList.DataSource = arrValues   MyCheckList.DataSource = arrValues   MyRadioList.DataSource = arrValues     'bind all the controls on the page   Page.DataBind()   End Sub  
How the Controls Are Bound

To understand what the controls are doing when data binding takes place, it's worth taking a look at the actual HTML that is created. You can do this by viewing the source of the page in your browser (if you're using Internet Explorer, right-click the page and select View Source). The following code shows how the simple list controls (the HTML <select> , ASP:DropDownList , and ASP:ListBox controls) are all persisted to the client as <select> elements. Each <option> element within the list has the value from the ArrayList items as both the value attribute and the text of the <option> element:

 <select name="MySelectList" id="MySelectList">    <option value="Microsoft">Microsoft</option>    <option value="Sun">Sun</option>    <option value="IBM">IBM</option>    <option value="Compaq">Compaq</option>    <option value="Oracle">Oracle</option> </select> 

The DataList control creates an HTML <table> and populates it with rows and cells containing the values from the ArrayList . The DataGrid control does the same, but adds a row containing the column name (in this case Item ) as well:

 <table cellspacing="0" rules="all" border="1">    <tr><td>Item</td></tr>    <tr><td>Microsoft</td></tr>    <tr><td>Sun</td></tr>    <tr><td>IBM</td></tr>    <tr><td>Compaq</td></tr>    <tr><td>Oracle</td></tr> </table> 

Both the CheckBoxList and RadioButtonList produce a table, but this time each cell contains either a checkbox control or a radio button control. The CheckBoxList control, which uses the values from the ArrayList as the captions for each checkbox “ it doesn't set the value attribute of each one “ is shown as follows:

 <td>    <span>       <input id="MyCheckList_0" type="checkbox" name="MyCheckList:0" />       <label for="MyCheckList_0">Microsoft</label>    </span> </td> 

However, the RadioButtonList control does set the value as well as the caption for each radio button, and all the radio buttons have the same name attribute (the name given to the control), so they operate as a radio button group as shown:

 <td>    <span value="Microsoft">       <input id="MyRadioList_0" type="radio" name="MyRadioList"              value="Microsoft" />       <label for="MyRadioList_0">Microsoft</label>    </span> </td> 

Finally, the output from the Repeater control is just a list of the values with no formatting, as shown:

 Microsoft Sun IBM Compaq Oracle 

Repeated-Value Binding to a HashTable Object

To demonstrate the differences in the way you handle other types of data source, the next example page binds the eight types of list control to a HashTable object rather than an ArrayList . Run the Repeated- Value Data Binding to a HashTable ( hashtable-binding.aspx ) example page to see the difference. One thing you'll immediately notice in Figure 7-5 is that two of each of the first three controls are included, and they contain different sets of values:

click to expand
Figure 7-5:

In this case, the data source is not a simple array of values, but a Dictionary -style object known as a HashTable . Each of the repeated items in the HashTable contains a Key and a Value . So, in this case, you can specify which of these you want to bind each control to. In the case of the first three list controls (the HTML <select> , ASP:DropDownList , and ASP:ListBox controls), we've bound one control to the Key of the HashTable and the other to the Value . The HTML section of the page is shown as follows:

  HTML <b>&lt;select&gt;</b> elements:<br />   <select id="MySelectList1" runat="server" /> &nbsp;   <select id="MySelectList2" runat="server" /><p />     <b>&lt;ASP:DropDownList&gt;</b> controls:<br />   <ASP:DropDownList id="MyDropDown1" runat="server" /> &nbsp;   <ASP:DropDownList id="MyDropDown2" runat="server" /><p />     <b>&lt;ASP:ListBox&gt;</b> controls:<br />   <ASP:ListBox id="MyASPList1" runat="server" /> &nbsp;   <ASP:ListBox id="MyASPList2" runat="server" /><p />     <b>&lt;ASP:DataGrid&gt;</b> control:<br />   <ASP:DataGrid id="MyDataGrid" runat="server" AutoGenerateColumns="false">   <Columns>   <ASP:BoundColumn HeaderText="Key" DataField="Key" />   <ASP:BoundColumn HeaderText="Value" DataField="Value"   DataFormatString="{0:C}" />   </Columns>   </ASP:DataGrid><p />     <b>&lt;ASP:Repeater&gt;</b> control:<br />   <ASP:Repeater id="MyRepeater" runat="server">   <ItemTemplate>   <%# Container.DataItem.Key %> =   <%# Container.DataItem.Value %><br />   </ItemTemplate>   </ASP:Repeater><p />     <b>&lt;ASP:DataList&gt;</b> control:<br />   <ASP:DataList id="MyDataList" runat="server">   <ItemTemplate>   '<%# Container.DataItem.Key %>' value:   <%# DataBinder.Eval(Container.DataItem, "Value", "{0:E}") %>   </ItemTemplate>   </ASP:DataList><p />     <b>&lt;ASP:CheckBoxList&gt;</b> control:<br />   <ASP:CheckBoxList id="MyCheckList" runat="server" /><p />     <b>&lt;ASP:RadioButtonList&gt;</b> control:<br />   <ASP:RadioButtonList id="MyRadioList" runat="server" /><p />  

The declaration of the HTML <select> , ASP:DropDownList , and ASP:ListBox controls at the top of the page, and the ASP:CheckBoxList and ASP:RadioButtonList controls at the bottom of the page, is the same as the previous example “ you just define the control itself. However, the definition of the other three list controls has to take into account the new structure of the data source.

Binding a DataGrid Control to a HashTable

The DataGrid control cannot figure out by itself how to handle a HashTable , and needs some help. This is done by setting the AutoGenerateColumns property of the control to False , and then using a <Columns> element and ASP:BoundColumn controls to specify where the values should come from. The two columns are bound to the Key and Value fields in each item. A DataFormatString is also specified for the Value column so that it is displayed in currency format:

  <ASP:DataGrid id="MyDataGrid" runat="server" AutoGenerateColumns="false">   <Columns>   <ASP:BoundColumn HeaderText="Key" DataField="Key" />   <ASP:BoundColumn HeaderText="Value" DataField="Value"   DataFormatString="{0:C}" />   </Columns>   </ASP:DataGrid>  
Binding a Repeater and a DataList Control to a HashTable

The Repeater and the DataList controls contain an <ItemTemplate> entry as in the previous example, where you used an ArrayList . However, now you can include two values in each template “ the Key property and the Value property. We refer to these as properties of the DataItem object.

Let's add some extra layout information in these two controls. In the Repeater control, add the equals sign between the Key and the Value , and a line break after each Key / Value pair. In the DataList control, wrap the output for each Key in single quotes, adding the word value: and formatting the Value property in scientific notation using the format string "{0:E}" . The code is repeated as follows:

  <b>&lt;ASP:Repeater&gt;</b> control:<br />   <ASP:Repeater id="MyRepeater" runat="server">   <ItemTemplate>   <%# Container.DataItem.Key %> =   <%# Container.DataItem.Value %><br />   </ItemTemplate>   </ASP:Repeater><p />     <b>&lt;ASP:DataList&gt;</b> control:<br />   <ASP:DataList id="MyDataList" runat="server">   <ItemTemplate>   '<%# Container.DataItem.Key %>'  value:   <%# DataBinder.Eval(Container.DataItem, "Value", "(0:E}") %>   </ItemTemplate>  
The Page_Load Event Handler

When the page loads, first create the HashTable and fill in some values, as shown:

  Sub Page_Load()     'create a HashTable of values to bind to   Dim tabValues As New HashTable(5)   tabValues.Add("Microsoft", 49.56)   tabValues.Add("Sun", 28.33)   tabValues.Add("IBM", 55)   tabValues.Add("Compaq", 20.74)   tabValues.Add("Oracle", 41.1)  

Then set the DataSource property of each of the controls on the page. In this case, you have to set at least the DataSource and DataTextField properties of the HTML <select> , ASP:DropDownList , and ASP:ListBox controls so that they know which field in the data source contains the values to display. In fact, this is exploited by having the first control in each pair display the Key values from the HashTable , and the second display the actual values of each item in the HashTable . You can also provide different values for the value attribute of the control if required as done for the second one of each control in the following code:

  'first <select> displays the Keys in the HashTable   MySelectList1.DataSource = tabValues   MySelectList1.DataTextField = "Key"     'second one displays the Values in the HashTable   'and uses the Keys as the <option> values   MySelectList2.DataSource = tabValues   MySelectList2.DataValueField = "Key"   MySelectList2.DataTextField = "Value"     'same applies to ASP: controls, except here   'we can also specify the format of the Key   MyDropDown1.DataSource = tabValues   MyDropDown1.DataTextField = "Key"   MyDropDown2.DataSource = tabValues   MyDropDown2.DataValueField = "Key"   MyDropDown2.DataTextField = "Value"   MyDropDown2.DataTextFormatString = "{0:F}"     MyASPList1.DataSource = tabValues   MyASPList1.DataTextField = "Key"   MyASPList2.DataSource = tabValues   MyASPList2.DataValueField = "Key"   MyASPList2.DataTextField = "Value"   MyASPList2.DataTextFormatString = "{0:C}"  

If you look back at Figure 7-5, you can also see the results of setting the DataTextFormatString property of the ASP:DropDownList and ASP:ListBox controls. For example, in the last four lines of the preceding code, the second ASP:ListBox control was bound to the HashTable so that the text of each <option> element is automatically formatted as a currency value.

Binding the DataGrid , Repeater , and DataList controls is easy because you specified how the columns should be mapped to the data source in the control definitions. You just need to set the DataSource property of each one:

  MyDataGrid.DataSource = tabValues   MyRepeater.DataSource = tabValues   MyDataList.DataSource = tabValues  

For the final two list controls, the CheckBoxList and RadioButtonList , you can specify both the DataValueField and the DataTextField properties. This is like the simple list controls such as the <select> list, and allows you to use different fields from the HashTable for the value attribute and the text for the control's caption:

  'in the CheckboxList we'll display the Title and   'use the Value as the control value   MyCheckList.DataSource = tabValues   MyCheckList.DataValueField = "Value"   MyCheckList.DataTextField = "Key"   'in the RadioList we'll display and format the   'Value and use the Key as the control value   MyRadioList.DataSource = tabValues   MyRadioList.DataValueField = "Key"   MyRadioList.DataTextField = "Value"   MyRadioList.DataTextFormatString = "Percentage rate {0:F}%"  

The final part of the code in the Page_Load event simply calls the DataBind method of the page to perform the data binding:

  Page.DataBind() 'bind all the controls on the page   End Sub  
How the Controls Are Bound

If you view the output that this page creates in the browser, you'll see that (unlike in the previous ArrayList example, where the value and text were the same) the second list in each group has the Key from each item in the HashTable as the value attribute of the <option> elements, and the Value from each item in the HashTable as the text of each <option> element. A section of this output is shown here:

 <select name="MySelectList2" id="MySelectList2">    <option value="Sun">28.33</option>    <option value="IBM">55</option>    <option value="Oracle">41.1</option>    <option value="Microsoft">49.56</option>    <option value="Compaq">20.74</option> </select> 

With the RadioButtonList , this technique also gives an output that specifies the Key from each item in the HashTable as the value attribute. The Value of each item in the HashTable is formatted and used as the text caption of the checkbox or radio button:

 <span value="Microsoft">    <input id="MyRadioList_3" type="radio" name="MyRadioList" value="Microsoft" />    <label for="MyRadioList_3">Percentage rate 49.56%</label> </span> 

Repeated-Value Binding to a DataView Object

Our third example of data binding is to a DataView object. For this example, we're using a custom user control that returns a DataView object from a database. We've provided the scripts and instructions for creating this database with the sample files, as well as a Microsoft Access database that you can use instead. All these are in the database folder of the examples for Chapters 8 to 11 (the data management examples).

Note

We'll discuss data access techniques later in the book “ it's not a vital topic here as long as you appreciate that basically each of the objects provides you with a set of data rows (a rowset) to which you can bind your controls. The next chapter discusses how to use these objects to extract data from a relational database.

The example page shown in Figure 7-6, Repeated-Value Data Binding to a DataView Object ( dataview binding.aspx ), contains the same eight list controls used in the previous two examples. However, now we are displaying information drawn from our database of Wrox books:

click to expand
Figure 7-6:

The HTML section of this page is basically the same as the first ArrayList example. The difference is the definition of the Repeater and the DataList controls. In each case, you need to specify the way to generate the content of the control from the values that are available in each list item (that is, each data row) within the source DataView .

The Repeater control generates no layout information by default, so you have to create a template using an <ItemTemplate> element. Specify a <div> element to get each item on a separate line, because the Repeater does not provide any intrinsic formatting. Inside the <div> element place the text, HTML, and definitions of the fields in the data source that you want to display. The following code displays the contents of three columns from the DataView “ the Title , ISBN , and PublicationDate and the way to format the PublicationDate column using the DataBinder.Eval method:

  <ASP:Repeater id="MyRepeater" runat="server">   <ItemTemplate>   <div>   <b><%# Container.DataItem("Title") %></b><br />   ISBN: <%# Container.DataItem("ISBN") %> &nbsp;   Published: <%# DataBinder.Eval(Container.DataItem, _   "PublicationDate", "{0:D}") %>   </div>   </ItemTemplate>   </ASP:Repeater>  

The DataList control creates an HTML table by default, so in this case you just need to specify the column and formatting information, along with any text and HTML you want to include in the table cells in each row:

  <ASP:DataList id="MyDataList" runat="server">   <ItemTemplate>   <b><%# Container.DataItem("Title") %></b><br />   ISBN: <%# Container.DataItem("ISBN") %> &nbsp;   Published: <%# DataBinder.Eval(Container.DataItem, _   "PublicationDate", "{0:D}") %>   </ItemTemplate>   </ASP:DataList>  

As you saw earlier, the DataGrid control is primarily designed to work with objects that are returned as the result of a database query, such as a DataView object. Hence it will automatically figure out what the column names and content are from the data source object. Therefore, it is not necessary to provide column information; you only need to place the DataGrid control in the page:

  <ASP:DataGrid id="MyDataGrid" runat="server" />  
The Page_Load Event Handler

This example uses a separate custom user control that returns a DataView object populated with details about some Wrox books. All the code in this page has to do is call a function in the user control to get back the DataView object:

  'get connection string from web.config   Dim strConnect As String   strConnect = ConfigurationSettings.AppSettings("DsnWroxBooksOleDb")     'create a SQL statement to select some rows from the database   Dim strSelect As String   strSelect = "SELECT * FROM BookList WHERE ISBN LIKE '18610053%'"     'create a variable to hold an instance of a DataView object   Dim objDataView As DataView     'get dataset from get-dataset-control.ascx user control   objDataView = ctlDataView.GetDataView(strConnect, strSelect)   If IsNothing(objDataView) Then Exit Sub  
Note

The details of how the control is inserted into the page, and how it gets the data from the database and creates the DataView object are covered in Chapter 8.

The next step is to set the DataSource and other properties of the controls in the page. The HTML <select> list and ASP:DropDownList and ASP:ListBox controls are mapped to the ISBN and Title columns in the DataView using the DataValueField and DataTextField properties of the controls:

  '<select> list displays values from the Title column   'and uses the ISBN as the <option> values     MySelectList.DataSource = objDataView   MySelectList.DataValueField = "ISBN"   MySelectList.DataTextField = "Title"     'do same with ASP: list controls   MyDropDown.DataSource = objDataView   MyDropDown.DataValueField = "ISBN"   MyDropDown.DataTextField = "Title"     MyASPList.DataSource = objDataView   MyASPList.DataValueField = "ISBN"   MyASPList.DataTextField = "Title"  

As mentioned earlier, the DataGrid control can figure out what the DataView contains, so just set the DataSource property:

  MyDataGrid.DataSource = objDataView  

The column information is specified in the definition of the Repeater and DataList controls; you only need to set their DataSource properties:

  MyRepeater.DataSource = objDataView   MyDataList.DataSource = objDataView  

For the CheckBoxList control, use the ISBN as the value attribute, and the Title as the text to be displayed for each checkbox caption:

  MyCheckList.DataSource = objDataView   MyCheckList.DataValueField = "ISBN"   MyCheckList.DataTextField = "Title"  

Specify the value property of each radio button in the RadioButtonList control to be ISBN , but this time display the content of the PublicationDate as the caption. It is formatted using a custom format string to display a long date:

  MyRadioList.DataSource = objDataView   MyRadioList.DataValueField = "ISBN"   MyRadioList.DataTextField = "PublicationDate"   MyRadioList.DataTextFormatString = "Published on {0:dddd, MMMM dd, yyyy}"  

All that's left is to activate the binding for all the controls on the page by calling the DataBind method of the Page object:

  Page.DataBind()  

Repeated-Value Binding to a DataSet Object

Our next example of data sources is the DataSet , and this is used in the Repeated-Value Data Binding to a DataSet Object ( dataset-binding.aspx ) page. This page creates exactly the same result as the previous example. The only difference is the creation of the data source, and how you actually perform the binding. The page includes some code that creates a DataSet object, and we'll discuss how this works until the next chapter. We'll focus here on the use of an object that has (or can have) multiple members as a data source.

As you'll see in the next chapter, a DataSet object can contain several tables of data (in DataTable objects). Therefore, when you bind to a DataSet , specify which table you want the values for the control to come from. This is done with the DataMember property of each control. For example, to set the binding for the <select> list with the id of MySelectList , use:

  MySelectList.DataSource = objDataSet 'specify the DataSet as the source   MySelectList.DataMember = "Books" 'use values from the table named "Books"   MySelectList.DataValueField = "ISBN" 'specify column to use for control values   MySelectList.DataTextField = "Title" 'specify column with text to display  

And, of course, the same technique is used for the rest of the controls on the page.

Repeated-Value Binding to a DataReader Object

The Repeated-Value Data Binding to a DataReader Object ( datareader-binding.aspx ) example page uses a DataReader as the data source for the bound controls. In general, using a DataReader is the preferred source of data for server-side data binding.

However, there is one important difference between this and the other data sources used. A DataReader is really just a pipe to the result of executing a query in a database. Once the database has processed the query and built up the result set, the DataReader gives a forward-only connection to that result set. You can only read the rows once.

So, you can't create a DataReader and bind it to multiple controls as in the previous examples. They worked because all of the other data sources (an ArrayList , HashTable , DataView, and DataSet ) are disconnected from the database.

Unlike the DataReader , these objects actually hold the data, which allows you to read the contents as many times as you like. Figure 7-7 shows the DataReader example page only, which contains just one data-bound control “ a DataGrid :

click to expand
Figure 7-7:

All you do is create your DataReader object in a variable named objDataReader , and bind it to the DataGrid control. The control can figure out what columns are in the rowset, and it displays the columnnames and the data automatically when you call the DataBind method:

  'create a DataReader object   Dim objDataReader As OleDbDataReader   ...   'code to connect to the database and build the rowset   ...   'set the DataSource property of the control   MyDataGrid.DataSource = objDataReader   MyDataGrid.DataBind() 'and bind the control  

You are calling the DataBind method of the control, rather than the DataBind method of the Page object as done in previous examples (as you've only got this one control).




Professional ASP. NET 1.1
Professional ASP.NET MVC 1.0 (Wrox Programmer to Programmer)
ISBN: 0470384611
EAN: 2147483647
Year: 2006
Pages: 243

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