Listing 7-60: Using the TreeView with a SqlDataSource control Using the TreeView control Ad Rotator The familiar AdRotator control was greatly enhanced in ASP.NET 2.0.. Lis
Trang 1<asp:Label ID="CountryLabel" Runat="server"
Text=’<%# Bind("Country") %>’>
</asp:Label></td>
<td style="width: 100px"></td>
<td style="width: 100px">
Phone:
<asp:Label ID="PhoneLabel" Runat="server"
Text=’<%# Bind("Phone") %>’>
</asp:Label><br />
Fax:
<asp:Label ID="FaxLabel" Runat="server"
Text=’<%# Bind("Fax") %>’>
</asp:Label><br />
</td>
</tr></table>
<asp:Button ID="Button1" Runat="server"
Text="Button" CommandName="edit" />
</td>
</tr></table>
</ItemTemplate>
</asp:FormView>
<asp:SqlDataSource ID="SqlDataSource1" Runat="server"
SelectCommand="SELECT * FROM [Customers]"
ConnectionString="<%$ ConnectionStrings:AppConnectionString1 %>">
</asp:SqlDataSource>
</div>
</form>
</body>
</html>
Other Databound Controls
ASP.NET 1.0/1.1 contained many other controls that could be bound to data sources ASP.NET 2.0
retained those controls, enhanced some, and added several additional bound controls to the toolbox
ASP.NET 3.5 continues to include these controls in its toolbox
DropDownList, ListBox, RadioButtonList, and CheckBoxList
Although the DropDownList, ListBox, and CheckBoxList controls largely remained the same from
ASP.NET 1.0/1.1 to ASP.NET 2.0, several new properties that you might find useful were added In addi-tion, ASP.NET 2.0 added new RadioButtonList and BulletedList controls All of these controls remain the same in ASP.NET 3.5
One of the new properties available in all these controls is theAppendDataBoundItemsproperty Setting this property toTruetells the DropDownList control to append data-bound list items to any
exist-ing statically declared items, rather then overwritexist-ing them as the ASP.NET 1.0/1.1 version would
have done
Another useful new property available to all these controls is theDataTextFormatString, which allows you to specify a string format for the display text of the DropDownList items
Trang 2Another control included in the ASP.NET toolbox is the TreeView control Because the TreeView can
display only hierarchical data, it can be bound only to the XmlDataSource and the SiteMapDataSource
controls Listing 7-59 shows a sample SiteMap file you can use for your SiteMapDataSource control
Listing 7-59: A SiteMap file for your samples
<siteMap>
<siteMapNode url="page3.aspx" title="Home" description="" roles="">
<siteMapNode url="page2.aspx" title="Content" description="" roles="" />
<siteMapNode url="page4.aspx" title="Links" description="" roles="" />
<siteMapNode url="page1.aspx" title="Comments" description="" roles="" />
</siteMapNode>
</siteMap>
Listing 7-60 shows how you can bind a TreeView control to a SiteMapDataSource control to generate
navigation for your Web site
Listing 7-60: Using the TreeView with a SqlDataSource control
<%@ Page Language="C#" %>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Using the TreeView control</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TreeView ID="TreeView1" Runat="server"
DataSourceID="SiteMapDataSource1">
</asp:TreeView>
<asp:SiteMapDataSource ID="SiteMapDataSource1" Runat="server" />
</div>
</form>
</body>
</html>
Ad Rotator
The familiar AdRotator control was greatly enhanced in ASP.NET 2.0 You can see the control by
using the SqlDataSource or XmlDataSource controls Listing 7-61 shows an example of binding the
AdRo-tator to a SqlDataSource control
Listing 7-61: Using the AdRotator with a SqlDataSource control
<asp:AdRotator ID="AdRotator1" runat="server"
DataSourceId="SqlDataSource1" AlternateTextField="AlternateTF"
ImageUrlField="Image" NavigateUrlField="NavigateUrl" />
For more information on the Ad Rotator control, see Chapter 5.
Trang 3The last control in this section is the new Menu control Like the TreeView control, it is capable of
displaying hierarchical data in a vertical pop-out style menu Also like the TreeView control, it can be
bound only to the XmlDataSource and the SiteMapDataSource controls Listing 7-62 shows how you can use the same SiteMap data used earlier in the TreeView control sample, and modify it to display using
the new Menu control
Listing 7-62: Using the Menu control with a SiteMap
<%@ Page Language="C#" %>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Using the Menu control</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Menu ID="Menu1" Runat="server" DataSourceID="SiteMapDataSource1">
</asp:Menu>
<asp:SiteMapDataSource ID="SiteMapDataSource1" Runat="server" />
</div>
</form>
</body>
</html>
For more information on using the Menu control, see Chapter 14.
Inline Data-Binding Syntax
Another feature of data binding in ASP.NET is inline data-binding syntax Inline syntax in ASP.NET
1.0/1.1 was primarily relegated to templated controls such as the DataList or the Repeater controls, and even then it was sometimes difficult and confusing to make it work as you wanted it to In ASP.NET
1.0/1.1, if you needed to use inline data binding, you might have created something like the procedure shown in Listing 7-63
Listing 7-63: Using DataBinders in ASP.NET 1.0
<asp:Repeater id=Repeater1 runat="server">
<HeaderTemplate>
<table>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<%# Container.DataItem("Name") %><BR/>
<%# Container.DataItem("Department") %><BR/>
<%# DataBinder.Eval(
Container.DataItem, "HireDate", "{0:mm dd yyyy}") %><BR/>
</td>
Continued
Trang 4</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
As you can see in this sample, you are using a Repeater control to display a series of employees Because
the Repeater control is a templated control, you use data binding to output the employee-specific data
in the proper location of the template Using theEvalmethod also allows you to provide formatting
information such as Date or Currency formatting at render-time
In later versions of ASP.NET, including 3.5, the concept of inline data binding remains basically the same,
but you are given a simpler syntax and several powerful new binding tools to use
Data-Binding Syntax Changes
ASP.NET contains three different ways to perform data binding First, you can continue to use the
exist-ing method of bindexist-ing, usexist-ing theContainer.DataItemsyntax:
<%# Container.DataItem("Name") %>
This is good because it means you won’t have to change your existing Web pages if you are migrating
from prior versions of ASP.NET But if you are creating new Web pages, you should probably use the
simplest form of binding, using theEvalmethod directly:
<%# Eval("Name") %>
You can also continue to format data using the formatter overload of theEvalmethod:
<%# Eval("HireDate", "{0:mm dd yyyy}" ) %>
In addition to these changes, ASP.NET includes a form of data binding called two-way data binding In
ASP.NET 1.0/1.1, using the data-binding syntax was essentially a read-only form of accessing data
Since the introduction of ASP.NET 2.0, two-way data binding has allowed you to support both read and
write operations for bound data This is done using theBindmethod, which, other than using a different
method name, works just like theEvalmethod:
<%# Bind("Name") %>
The newBindmethod should be used in new controls such as the GridView, DetailsView, or FormView,
where auto-updates to the data source are implemented
When working with the data binding statements, remember that anything between the<%# %>delimiters
is treated as an expression This is important because it gives you additional functionality when data
binding For example, you could append additional data:
<%# "Foo " + Eval("Name") %>
Or you can even pass the evaluated value to a method:
<%# DoSomeProcess( Eval("Name") )%>
Trang 5XML Data Binding
Because XML is becoming ever more prevalent in applications, ASP.NET also includes several ways to
bind specifically to XML data sources These new data binding expressions give you powerful ways of
working with the hierarchical format of XML Additionally, except for the different method names, these binding methods work exactly the same as theEvalandBindmethods discussed earlier These binders should be used when you are using the XmlDataSource control The first binding format that uses the
XPathBinderclass is shown in the following code:
<% XPathBinder.Eval(Container.DataItem, "employees/employee/Name") %>
Notice that rather than specifying a column name as in theEvalmethod, theXPathBinderbinds the
result of an XPath query Like the standardEvalexpression, the XPath data binding expression also has
a shorthand format:
<% XPath("employees/employee/Name") %>
Also, like theEvalmethod, the XPath data binding expression supports applying formatting to the data:
<% XPath("employees/employee/HireDate", "{0:mm dd yyyy}") %>
TheXPathBinderreturns a single node using the XPath query provided Should you want to return
multiple nodes from the XmlDataSource Control, you can use the class’sSelectmethod This method
returns a list of nodes that match the supplied XPath query:
<% XPathBinder.Select(Container.DataItem,"employees/employee") %>
Or use the shorthand syntax:
<% XpathSelect("employees/employee") %>
Expressions and Expression Builders
Finally, ASP.NET introduces the concept of expressions and expression builders Expressions are state-ments that are parsed by ASP.NET at runtime in order to return a data value ASP.NET automatically
uses expressions to do things like retrieve the database connection string when it parses the
SqlData-Source control, so you may have already seen these statements in your pages An example of the connec-tion string Expression is shown in Listing 7-64
Listing 7-64: A connection string Expression
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
SelectCommand="SELECT * FROM Customers"></asp:SqlDataSource>
When ASP.NET is attempting to parse an ASP.NET Web page, it looks for expressions contained in the
<%$ %>delimiters This indicates to ASP.NET that this is an expression to be parsed As shown in the
previous listing, it attempts to locate theNorthwindConnectionStringvalue from the web.config file
ASP.NET knows to do this because of theConnectionStringsexpression prefix, which tells ASP.NET to use theConnectionStringsExpressionBuilderclass to parse the expression
Trang 6ASP.NET includes several expression builders, including one for retrieving values from the
AppSet-tings section ofweb.config: one for retrieving ConnectionStrings as shown in Listing 7-64, and one for
retrieving localized resource file values Listings 7-65 and 7-66 demonstrate using the
AppSettingsEx-pressionBuilderand theResourceExpressionBuilder
Listing 7-65: Using AppSettingsExpressionBuilder
<asp:Label runat="server" ID="lblAppSettings"
Text="<%$ AppSettings: LabelText %>"></asp:Label>
Listing 7-66: Using ResourceExpressionBuilder
<asp:Label runat="server" ID="lblResource"
Text="<%$ Resources: TEST %>"></asp:Label>
In addition to using the expression builder classes, you can also create your own expressions by deriving
a class from theSystem.Web.Compilation.ExpressionBuilderbase class This base class provides you
with the overridable methods you need to implement if you want ASP.NET to parse your expression
properly Listing 7-67 shows a simple custom expression builder
Listing 7-67: Using a simple custom expression builder
VB
Imports System;
Imports System.CodeDom;
Imports System.Web.Compilation;
Imports System.Web.UI;
<ExpressionPrefix("MyCustomExpression")>
<ExpressionEditor("MyCustomExpressionEditor")>
Public Class MyCustomExpression Inherits ExpressionBuilder
Public Overrides Function GetCodeExpression(ByVal entry As BoundPropertyEntry, ByVal parsedData As object, ByVal context As ExpressionBuilderContext)
As System.CodeDom.CodeExpression Return New CodeCastExpression("Int64", new CodePrimitiveExpression(1000)) End Function
End Class
C#
using System;
using System.CodeDom;
using System.Web.Compilation;
using System.Web.UI;
[ExpressionPrefix("MyCustomExpression")]
[ExpressionEditor("MyCustomExpressionEditor")]
public class MyCustomExpression : ExpressionBuilder
{
public override System.CodeDom.CodeExpression
Trang 7GetCodeExpression(BoundPropertyEntry entry, object parsedData,
ExpressionBuilderContext context) {
return new CodeCastExpression("Int64", new CodePrimitiveExpression(1000));
}
}
In examining this sample, notice several items First, you have derived theMyCustomExpressionclass
fromExpressionBuilderas I discussed earlier Second, you have overridden theGetCodeExpression
method This method supplies you with several parameters that can be helpful in executing this method, and it returns aCodeExpressionobject to ASP.NET that it can execute at runtime to retrieve the data
value
TheCodeExpressionclass is a base class in NET’s CodeDom infrastructure Classes that are derived
from theCodeExpressionclass provide abstracted ways of generating NET code, whether VB or C#.
This CodeDom infrastructure is what helps you create and run code dynamically at runtime.
TheBoundPropertyEntryparameter entry tells you exactly which property the expression is bound
to For example, in Listings 7-58 and 7-59, the Label’sTextproperty is bound to theAppSettingsand
Resourcesexpressions The object parameterparsedDatacontains any data that was parsed and returned
by theParseExpressionmethod that you see later on in the chapter Finally, the
ExpressionBuilder-Contextparameter context allows you to reference the virtual path or templated control associated with the expression
In the body of theGetCodeExpressionmethod, you are creating a newCodeCastExpressionobject,
which is a class derived from theCodeExpressionbase class TheCodeCastExpressiontells NET to
generate the appropriate code to execute a cast from one data type to another In this case, you are casting the value 1000 to an Int64 datatype When NET executes theCodeCastExpression, it is (in a sense)
writing the C# code ((long)(1000)), or (if your application was written in VB) CType(1000,Long) Note
that a wide variety of classes derive from theCodeExpressionclass that you can use to generate your
final code expression
The final lines to note are the two attributes that have been added to the class TheExpressionPrefixand ExpressionEditorattributes help NET figure out that this class should be used as an expression, and
they also help NET locate the proper expression builder class when it comes time to parse the expression After you have created your expression builder class, you let NET know about it You do this by adding
anexpressionBuildersnode to the compilation node in yourweb.configfile Notice that the value
of theExpressionPrefixis added to theexpressionBuilderto help ASP.NET locate the appropriate
expression builder class at runtime
<compilation debug="true" strict="false" explicit="true">
<expressionBuilders>
<add expressionPrefix="MyCustomExpression" type="MyCustomExpression"/>
</expressionBuilders>
</compilation>
TheGetCodeExpressionmethod is not the only member available for overriding in the
Expression-Builderclass Several other useful members include theParseExpression,SupportsEvaluate, and
EvaluateExpressionmethods
Trang 8TheParseExpressionmethod lets you pass parsed expression data into theGetCodeExpressionmethod.
For example, in Listing 7-60, theCodeCastExpressionvalue 1000 was hard-coded If, however, you want
to allow a developer to pass that value in as part of the expression, you simply use theParseExpression
method as shown in Listing 7-68
Listing 7-68: Using ParseExpression
VB
Imports System;
Imports System.CodeDom;
Imports System.Web.Compilation;
Imports System.Web.UI;
<ExpressionPrefix("MyCustomExpression")>
<ExpressionEditor("MyCustomExpressionEditor")>
Public Class MyCustomExpression Inherits ExpressionBuilder
Public Overrides Function
GetCodeExpression(ByVal entry As BoundPropertyEntry, ByVal parsedData As object, ByVal context As ExpressionBuilderContext)
As System.CodeDom.CodeExpression Return New CodeCastExpression("Int64", new CodePrimitiveExpression(passedData)) End Function
Public Overrides Function ParseExpression
(ByVal expression As String, ByVal propertyType As Type, ByVal context As ExpressionBuilderContext) As Object Return expression
End Function
End Class
C#
using System;
using System.CodeDom;
using System.Web.Compilation;
using System.Web.UI;
[ExpressionPrefix("MyCustomExpression")]
[ExpressionEditor("MyCustomExpressionEditor")]
public class MyCustomExpression : ExpressionBuilder
{
public override System.CodeDom.CodeExpression
GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
{
return new CodeCastExpression("Int64", new CodePrimitiveExpression(parsedData));
}
Trang 9public override object ParseExpression
(string expression, Type propertyType, ExpressionBuilderContext context)
{
return expression;
}
}
The last twoExpressionBuilderoverrides to examine are theSupportsEvaluateand EvaluateExpres-sionmembers You need to override these methods if you are running your Web site in a no-compile
scenario (you have specifiedcompilationMode = "never"in your @Page directive) The SupportEvalu-ateproperty returns a Boolean indicating to ASP.NET whether this expression can be evaluated while a page is executing in no-compile mode IfTrueis returned and the page is executing in no-compile mode, theEvaluateExpressionmethod is used to return the data value rather than theGetCodeExpression
method TheEvaluateExpressionreturns an object representing the data value See Listing 7-69
Listing 7-69: Overriding SupportsEvaluate and EvaluateExpression
VB
Imports System;
Imports System.CodeDom;
Imports System.Web.Compilation;
Imports System.Web.UI;
<ExpressionPrefix("MyCustomExpression")>
<ExpressionEditor("MyCustomExpressionEditor")>
Public Class MyCustomExpression Inherits ExpressionBuilder
Public Overrides Function
GetCodeExpression(ByVal entry As BoundPropertyEntry,
ByVal parsedData As object, ByVal context As ExpressionBuilderContext)
As System.CodeDom.CodeExpression Return New CodeCastExpression("Int64",
new CodePrimitiveExpression(pasedData)) End Function
Public Overrides Function ParseExpression
(ByVal expression As String, ByVal propertyType As Type,
ByVal context As ExpressionBuilderContext) As Object Return expression
End Function
Public Overrides ReadOnly Property SupportsEvaluate as Boolean
Get
Return True End Get
End Property
Public Overrides Function EvaluateExpression(ByVal target As Object,
ByVal Entry As BoundPropertyEntry, ByVal parsedData As Object,
ByVal context As ExpressionBuilderContext) as Object
Continued
Trang 10Return parsedData;
End Function
End Class
C#
using System;
using System.CodeDom;
using System.Web.Compilation;
using System.Web.UI;
[ExpressionPrefix("MyCustomExpression")]
[ExpressionEditor("MyCustomExpression123Editor")]
public class MyCustomExpression : ExpressionBuilder
{
public override System.CodeDom.CodeExpression
GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
{
return new CodeCastExpression("Int64", new CodePrimitiveExpression(parsedData));
}
public override object ParseExpression
(string expression, Type propertyType, ExpressionBuilderContext context) {
return expression;
}
public override bool SupportsEvaluate
{
get { return true;
} }
public override object EvaluateExpression(object target,
BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
{
return parsedData;
}
}
As shown in Listing 7-69, you can simply returnTruefrom theSupportsEvaluateproperty if you want
to override theEvaluateExpressionmethod Then all you do is return an object from the
EvaluateEx-pressionmethod