1. Introducing Data Binding
The basic principle of data
binding is this: you tell a control where to find your data and how you
want it displayed, and the control handles the rest of the details. Data
binding in ASP.NET is superficially similar to data binding in the
world of desktop or client/server applications, but in truth, it's
fundamentally different. In those environments, data binding involves
creating a direct connection between a data source and a control in an
application window. If the user changes a value in the on-screen
control, the data in the linked database is modified automatically.
Similarly, if the database changes while the user is working with it
(for example, another user commits a change), the display can be
refreshed automatically.
This type of data binding
isn't practical in the ASP.NET world, because you can't effectively
maintain a database connection over the Internet. This "direct" data
binding also severely limits scalability and reduces flexibility. In
fact, data binding has acquired a bad reputation for exactly these
reasons.
ASP.NET data binding, on the
other hand, has little in common with direct data binding. ASP.NET data
binding works in one direction only. Information moves from a data object into
a control. Then the data objects are thrown away, and the page is sent
to the client. If the user modifies the data in a data-bound control,
your program can update the corresponding record in the database, but
nothing happens automatically.
ASP.NET data binding is
much more flexible than old-style data binding. Many of the most
powerful data binding controls, such as the GridView and DetailsView,
give you unprecedented control over the presentation of your data,
allowing you to format it, change its layout, embed it in other ASP.NET
controls, and so on.
1.1. Types of ASP.NET Data Binding
Two types of ASP.NET data
binding exist: single-value binding and repeated-value binding.
Single-value data binding is by far the simpler of the two, whereas
repeated-value binding provides the foundation for the most advanced
ASP.NET data controls.
15.1.1.1. Single-Value, or "Simple," Data Binding
You can use single-value data binding
to add information anywhere on an ASP.NET page. You can even place
information into a control property or as plain text inside an HTML tag.
Single-value data binding doesn't necessarily have anything to do with
ADO.NET. Instead, single-value data binding allows you to take a
variable, a property, or an expression and insert it dynamically into a
page.
1.1.2. Repeated-Value, or "List," Binding
Repeated-value data binding
allows you to display an entire table (or just a single field from a
table). Unlike single-value data binding, this type of data binding
requires a special control that supports it. Typically, this will be a
list control such as CheckBoxList or ListBox, but it can also be a much
more sophisticated control such as the GridView.
You'll know that a control supports repeated-value data binding if it
provides a DataSource property. As with single-value binding,
repeated-value binding doesn't necessarily need to use data from a
database, and it doesn't have to use the ADO.NET objects. For example,
you can use repeated-value binding to bind data from a collection or an
array.
1.2. How Data Binding Works
Data binding works a little
differently depending on whether you're using single-value or
repeated-value binding. To use single-value binding, you must insert a
data binding expression into the markup in the .aspx file (not the
code-behind file). To use repeated-value binding, you must set one or
more properties of a data control. Typically, you'll perform this
initialization when the Page.Load event fires.
Once you specify data binding,
you need to activate it. You accomplish this task by calling the
DataBind() method. The DataBind() method is a basic piece of
functionality supplied in the Control class. It automatically binds a
control and any child controls that it contains. With repeated-value
binding, you can use the DataBind() method of the specific list control
you're using. Alternatively, you can bind the whole page at once by
calling the DataBind() method of the current Page object. Once you call
this method, all the data binding expressions in the page are evaluated
and replaced with the specified value.
Typically, you call the
DataBind() method in the Page.Load event handler. If you forget to use
it, ASP.NET will ignore your data binding expressions, and the client
will receive a page that contains empty values.
This
is a general description of the whole process. To really understand
what's happening, you need to work with some specific examples.
2. Single-Value Data Binding
Single-value data binding
is really just a different approach to dynamic text. To use it, you add
special data binding expressions into your .aspx files. These
expressions have the following format:
<%# expression_goes_here %>
This may look like a script
block, but it isn't. If you try to write any code inside this tag, you
will receive an error. The only thing you can add is a valid data
binding expression. For example, if you have a public or protected
variable named Country in your page, you could write the following:
<%# Country %>
When you call the
DataBind() method for the page, this text will be replaced with the
value for Country (for example, Spain). Similarly, you could use a
property or a built-in ASP.NET object as follows:
<%# Request.Browser.Browser %>
This would substitute a
string with the current browser name (for example, IE). In fact, you can
even call a function defined on your page, or execute a simple
expression, provided it returns a result that can be converted to text
and displayed on the page. Thus, the following data binding expressions
are all valid:
<%# GetUserName(ID) %>
<%# 1 + (2 * 20) %>
<%# "John " & "Smith" %>
Remember, you place these data binding expressions in the markup portion of your .aspx file, not your code-behind file.
2.1. A Simple Data Binding Example
This section shows a simple
example of single-value data binding. The example has been stripped to
the bare minimum amount of detail needed to illustrate the concept.
You start with a variable defined in your Page class, which is called TransactionCount:
Public Partial Class SimpleDataBinding
Inherits System.Web.UI.Page
Protected TransactionCount As Integer
' (Additional code omitted.)
End Class
Note that this variable
must be designated as public, protected, or internal, but not private.
If you make the variable private, ASP.NET will not be able to access it
when it's evaluating the data binding expression.
Now, assume that this value is
set in the Page.Load event handler using some database lookup code. For
testing purposes, the example skips this step and hard-codes a value:
Protected Sub Page_Load(ByVal sender As Object, _
ByVal e As EventArgs) Handles Me.Load
' (You could use database code here
' to look up a value for TransactionCount.)
TransactionCount = 10
' Now convert all the data binding expressions on the page.
Me.DataBind()
End Sub
Two actions actually take
place in this event handler: the TransactionCount variable is set to
10, and all the data binding expressions on the page are bound.
Currently, no data binding expressions exist, so this method has no
effect. Notice that this example uses the Me keyword to refer to the
current page. You could just write DataBind() without the Me keyword,
because the default object is the current Page object. However, using
the Me keyword makes it a bit clearer what object is being used.
To make this data binding
accomplish something, you need to add a data binding expression.
Usually, it's easiest to add this value directly to the markup in the
.aspx file. To do so, click the Source button at the bottom of the web
page designer window. Figure 1 shows an example with a Label control.
To add your expression, find the tag for the Label control. Modify the text inside the label as shown here:
<asp:Label id="lblDynamic" runat="server" Font-Size="X-Large">
There were <%# TransactionCount %> transactions today.
I see that you are using <%# Request.Browser.Browser %>.
</asp:Label>
This example uses two
separate data binding expressions, which are inserted along with the
normal static text. The first data binding expression references the
TransactionCount variable, and the second uses the built-in Request
object to determine some information about the user's browser. When you
run this page, the output looks like Figure 2.
The data binding expressions
have been automatically replaced with the appropriate values. If the
page is posted back, you could use additional code to modify
TransactionCount, and as long as you call the DataBind() method, that
information will be popped into the page in the data binding expression
you've defined.
If, however, you forget to
call the DataBind() method, the data binding expressions will be
ignored, and the user will see a somewhat confusing window that looks
like Figure 3.
NOTE
When using single-value
data binding, you need to consider when you should call the DataBind()
method. For example, if you made the mistake of calling it before you
set the TransactionCount variable, the corresponding expression would
just be converted to 0. Remember, data binding is a one-way street. This
means changing the TransactionCount variable after you've used the
DataBind() method won't produce any visible effect. Unless you call the
DataBind() method again, the displayed value won't be updated.
2.2. Simple Data Binding with Properties
The previous example uses a data
binding expression to set static text information inside a label tag.
However, you can also use single-value data binding to set other types
of information on your page, including control properties. To do this,
you simply have to know where to put the data binding expression in the
web page markup.
For example, consider
the following page, which defines a variable named URL and uses it to
point to a picture in the application directory:
Public Partial Class DataBindingUrl
Inherits System.Web.UI.Page
Protected URL As String
Protected Sub Page_Load(ByVal sender As Object, _
ByVal e As EventArgs) Handles Me.Load
URL = "Images/picture.jpg"
Me.DataBind()
End Sub
End Class
You can now use this URL to create a label, as shown here:
<asp:Label id="lblDynamic" runat="server"><%# URL %></asp:Label>
You can also use it for a check box caption:
<asp:CheckBox id="chkDynamic" Text="<%# URL %>" runat="server" />
or you can use it for a target for a hyperlink:
<asp:Hyperlink id="lnkDynamic" Text="Click here!" NavigateUrl="<%# URL %>"
runat="server" />
You can even use it for a picture:
<asp:Image id="imgDynamic" ImageUrl="<%# URL %>" runat="server" />
The only trick is that you need to edit these control tags manually. Figure 4 shows what a page that uses all these elements would look like.
2.3. Problems with Single-Value Data Binding
Before you start using
single-value data binding techniques in every aspect of your ASP.NET
programs, you should consider some of the serious drawbacks this
approach can present:
Putting code into a page's user interface:
One of ASP.NET's
great advantages is that it allows developers to separate the user
interface code (the HTML and control tags in the .aspx file) from the
actual code used for data access and all other tasks (in the code-behind
file). However, overenthusiastic use of single-value data binding can
encourage you to disregard that distinction and start coding function
calls and even operations into your page. If not carefully managed, this
can lead to complete disorder. (On the other hand, in a carefully
designed system like ASP.NET MVC, it can lead to surprisingly lean,
modern markup—if you know what you're doing.
Fragmenting code:
When using data
binding expressions, it may not be obvious where the functionality
resides for different operations. This is particularly a problem if you
blend both approaches—for example, if you use data binding to fill a
control and also modify that control directly in code. Even worse, the
data binding code may have certain dependencies that aren't immediately
obvious. If the page code changes, or a variable or function is removed
or renamed, the corresponding data binding expression could stop
providing valid information without any explanation or even an obvious
error. All of these details make it more difficult to maintain your
code, and make it more difficult for multiple developers to work
together on the same project.
Of course, some developers
love the flexibility of single-value data binding and use it to great
effect, making the rest of their code more economical and streamlined.
It's up to you to be aware of (and avoid) the potential drawbacks.
NOTE
In one case, single-value data binding is quite useful—when building templates.
Templates declare a block of markup that's reused for each record in a
table. However, they work only with certain rich data controls, such as
the GridView.
2.4. Using Code Instead of Simple Data Binding
If you decide not to use
single-value data binding, you can accomplish the same thing using
code. For example, you could use the following event handler to display
the same output as the first label example:
Protected Sub Page_Load(ByVal sender As Object, _
ByVal e As EventArgs) Handles Me.Load
TransactionCount = 10
lblDynamic.Text = "There were " & TransactionCount.ToString()
lblDynamic.Text &= " transactions today. "
lblDynamic.Text &= "I see that you are using " & Request.Browser.Browser
End Sub
This code dynamically fills in the label without using data binding. The trade-off is more code.
When
you use data binding expressions, you end up complicating your markup
with additional details about your code (such as the names of the
variables in your code-behind class). When you use the code-only
approach, you end up doing the reverse—complicating your code with
additional details about the page markup (like the text you want to
display). In many cases, the best approach depends on your specific
scenario. Data binding expressions are great for injecting small bits of
information into an otherwise detailed page. The dynamic code approach
gives you more flexibility, and works well when you need to perform more
extensive work to shape the page (for example, interacting with
multiple controls, changing content and formatting, retrieving the
information you want to display from different sources, and so on).