2. Other Data-Binding Methods
In ASP.NET, data-binding expressions go far beyond a read-only evaluation of enumerable and tabular data. In addition to DataBinder,
ASP.NET provides a class that can bind to the result of XPath
expressions that are executed against an object that implements the IXPathNavigable interface. This class is named XPathBinder; it plays the same role as DataBinder, except it works on XML data. The XPathBinder class backs up a new data-binding method named XPath.
ASP.NET
also supports declarative two-way data binding, meaning that you can
read and write data item properties through a new data-binding method
named Bind.
Finally,
ASP.NET supports user-defined expressions that operate outside the
boundaries of data-binding operations. It might sound weird that I
discuss non-data-binding expressions in a section explicitly dedicated
to data-binding expressions. The reason I mention this option here is
to avoid confusion, as the syntax for custom expressions is nearly
identical.
The XPath Method
Starting
with ASP.NET 2.0, data-bound controls can be associated with raw XML
data. You can bind XML data in version 1.x, but you have to first fit
XML data into a relational structure such as a DataSet. When a templated control such as DataList or Repeater is bound to an XML data source, individual XML fragments can be bound inside the template using the XPathBinder object.
The XPathBinder.Eval method accepts an XmlNode
object along with an XPath expression, and it evaluates and returns the
result. The output string can be formatted if a proper format string is
specified. XPathBinder.Eval casts the container object to IXPathNavigable.
This is a prerequisite to applying the XPath expression. If the object
doesn’t implement the interface, an exception is thrown. The IXPathNavigable
interface is necessary because in the .NET Framework the whole XPath
API is built for, and works only with, objects that provide a navigator
class. The goal of the interface is to create an XPath navigator object
for the query to run.
Like DataBinder, the XPathBinder
class supports a simplified syntax for its evaluator method. The syntax
assumes a default container context that is the same object that is
tracked for the data binder. The following example demonstrates using
the simplified XPath data-binding syntax:
<%# XPath("Orders/Order/Customer/LastName") %>
The output value is the object returned by XPathBinder.Eval converted to a string. Internally, XPathBinder.Eval gets a navigator object from the data source and evaluates the expression. The managed XPath API is used.
The XPathSelect Method
The XPathBinder class also features a Select
method. The method executes an XPath query and retrieves a nodeset—an
enumerable collection of XML nodes. This collection can be assigned as
a late-bound value to data-bound controls (such as the Repeater control). An equivalent simplified syntax exists for this scenario, too:
<asp:Repeater runat="server" DataSource='<%# XPathSelect("orders/order/summary") %>'>
...
</asp:Repeater>
XPathSelect
is the keyword you use in data-binding expressions to indicate the
results of an XPath query run on the container object. If the container
object does not implement IXPathNavigable, an exception is thrown. Like Eval and XPath, XPathSelect assumes a default data item context object.
The Bind Method
ASP.NET supports two-way data binding—that is, the capability to bind
data to controls and submit changes back to the database. The Eval method is representative of a one-way data binding that automates data reading but not data writing. The new Bind method can be used whenever Eval is accepted and through a similar syntax:
<asp:TextBox Runat="server" ID="TheNotes" Text='<%# Bind("notes") %>' />
The big difference is that Bind works in both directions—reading and writing. For example, when the Text property is being set, Bind behaves exactly like Eval. In addition, when the Text property is being read, Bind stores the value into a collection. Enabled ASP.NET data-bound controls (for example, the new FormView
control and other templated controls) automatically retrieve these
values and use them to compose the parameter list of the insert or edit
command to run against the data source. The argument passed to Bind must match the name of a parameter in the command. For example, the text box just shown provides the value for the @notes parameter.
User-Defined Dynamic Expressions
Data-binding
expressions are not really dynamic expressions because they are
evaluated only within the context of a data-binding call. ASP.NET
provides a made-to-measure infrastructure for dynamic expressions based
on a new breed of components—the expression builders. (I cover
expression builders in Programming Microsoft ASP.NET 2.0 Applications: Advanced Topics.)
Dynamic expressions have a syntax that is similar to data binding, except that they use the $
prefix instead of #. Dynamic expressions are evaluated when the page
compiles. The content of the expression is extracted, transformed into
code, and injected into the code created for the page. A few predefined
expression builders exist, as listed in Table 1.
Table 1. Custom Expressions
Syntax | Description |
---|
AppSettings:XXX | Returns the value of the specified setting from the <appSettings> section of the configuration file. |
ConnectionStrings:XXX[.YYY] | Returns the value of the specified XXX string from the <connectionStrings>
section of the configuration file. The optional YYY parameter indicates
which attribute is read from the section. It can be either connectionString (default) or providerName. |
Resources:XXX, YYY | Returns the value of the YYY global resource read from the XXX resource file (.resx). |
To declaratively bind a control property to the value of the expression, you follow the schema shown here:
The exact syntax is defined
by the builder associated with each expression. Note, though, that
literal expressions are not permitted in the body of the page. In other
words, you can use expressions only to set a control property. You
can’t have the following:
<h1><%$ AppSettings:AppVersionNumber %></h1>
Instead, you should wrap the expression in a server control, the simplest of which would be the Literal control. The following code generates the page in Figure 2:
<h1><asp:Literal runat="server"
Text="<%$ Resources:Resource, AppWelcome %>" /></h1>
<hr />
<b>Code version <asp:Literal runat="server"
Text="<%$ AppSettings:AppVersionNumber %>" /></b>
Needless to say, you need to have an AppWelcome string resource in the App_GlobalResource and an AppVersionNumber setting in the web.config file.
<appSettings>
<add key="AppVersionNumber" value="8.2.2001" />
</appSettings>
The remaining expression—ConnectionStrings—is extremely helpful with data source controls to avoid hard-coding the connection string in the .aspx file.