|
今天谈下.NET中的数据绑定表达式。 数据绑定表达式必须包含在<%#和%>字符之间。格式如下:
<
tagprefix:tagname
property
='<%#
data-binding expression %
>
' runat="server" />
或者如下:
<%
# data
-
binding expression
%>
ASP.NET 支持分层数据绑定模型,数据绑定表达式使用 Eval 和 Bind 方法将数据绑定到控件,并将更改提交回数据库。 Eval 方法是静态单向(只读)方法,所以Eval 函数用于单向(只读)绑定,该方法采用数据字段的值作为参数并将其作为字符串返回。 Bind 方法支持读/写功能,所以Bind 函数用于双向(可更新)绑定。该方法可以检索数据绑定控件的值并将任何更改提交回数据库。 XPath 方法支持对XML类型的数据源提供支持。
数据绑定表达式都可以出现在页面的哪个位置呢?
一,可以将数据绑定表达式包含在服务器控件或者普通的html元素的开始标记中属性名/属性值对的值侧。例如:
<
asp:TextBox
ID
="TextBox1"
runat
="server"
Text
='<%#数据绑定表达式%
>
' >
</
asp:TextBox
><
br
/>
注意条款:此时数据的绑顶表达式可以是一个变量,也可以是一个带返回值的C#或者VB.NET方 法,还可以是某个控件的某个属性的值,也可以是C#或者VB.NET对象的某个字段或者属性的值等 等。当然也可以直接就是一个字符串,例如"hello"。
如果此时的数据绑定表达式是Eval("数据库中某个表的某个字段")等,那么必须把TextBox1放在某 个循环显示的控件的模板中才正确,否则会提示:Eval()、XPath() 和 Bind() 这类数据绑定方 法只能在数据绑定控件的上下文中使用。其实就是想让你把TextBox1放在像Repeater,DataList, GridView这样的控件的模板中。
二,数据绑定绑定表达式包含在在页面中的任何位置。例如
<
form
id
="form1"
runat
="server"
>
<
div
>
<%
#
Eval
(
"
数据绑定表达式1
"
)
%>
<%
#
Eval
(
"
数据绑定表达式2
"
)
%>
</
div
>
</
form
>
同样遵循"一"的注意条款。 如果此时的数据绑定表达式是Eval("数据库中某个表的某个字段")等,那么必须把 <%#Eval("数 据绑定表达式1")%> <%#Eval("数据绑定表达式2")%> 放在像Repeater,DataList, GridView这样的控件的模板中。
三,可以将数据绑定表达式包含在Javascript代码中,从而实现在Javascript中调用C#或者 VB.NET的方法。例如: Deafult2.aspx:
<%
@ Page Language
=
"
C#
"
AutoEventWireup
=
"
true
"
CodeFile
=
"
Default2.aspx.cs
"
Inherits
=
"
Default2
"
%>
<!
DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>
<
html
xmlns
="http://www.w3.org/1999/xhtml"
>
<
head
runat
="server"
>
<
title
>
无标题页
</
title
>
<
script
language
="javascript"
type
="text/javascript"
>
function
GetStr() {
var
a; a
=
''
; a
=
'
<%#CSharpToJavascript()%>
'
//
调用c#的方法
alert(a); }
</
script
>
</
head
>
<
body
>
<
form
id
="form1"
runat
="server"
>
<
div
>
<
input
id
="Button1"
type
="button"
value
="Javascript调用c#的方法!"
onclick
="GetStr()"
/</div
>
</
form
>
</
body
>
</
html
>
Default2.cs:
using
System;
using
System.Data;
using
System.Configuration;
using
System.Collections;
using
System.Web;
using
System.Web.Security;
using
System.Web.UI;
using
System.Web.UI.WebControls;
using
System.Web.UI.WebControls.WebParts;
using
System.Web.UI.HtmlControls;
public
partial
class
Default2 : System.Web.UI.Page {
protected
void
Page_Load(
object
sender, EventArgs e) { Page.DataBind();
//
方法有返回值的要先绑定,才能实现Javascript调用c#的方法!
}
public
string
CSharpToJavascript() {
return
"
Javascript调用c#的方法!
"
; } }
数据绑定表达式都可以是什么类型呢? 1,可以是一个变量 例如:<asp:Label ID="Label1" runat="server" Text="<%#变量名%>"></asp:Label> 2,可以是服务器控件的属性值 例如: <asp:Label ID="Label1" runat="server" Text="<%#TextBox2.Text %>"></asp:Label> 3,可以是一个数组等集合对象 例如把一个数组绑定到列表控件,例如ListBox等,或者Repeater,DataList,GridView这样的控 件等,此时只需要把属性DataSource='<%# 数组名%>' 。
4,可以是一个表达式 例如:Person是一个对象,Name和City是它的2个属性,则数据绑定表达式可以这样写:
<%#(Person.Name + " " + Person.City)%>。 5,可以是一个方法 例如:<%#GetUserName()%>。GetUserName()是一个已经定义的C#方法,一般要求有 返回值。 6,可以是用Eval,DateBind.Eval取得的数据表的字段,这个是最常见的了,不再举例。
注意:如果数据绑定表达式作为属性的值,只要数据绑定表达式中没有出现双引号,那么<%#数据绑定表达式%>的最外层 用双引号或者单引号都可以。如果数据绑定表达式中出现双引号,则<%#数据绑定表达式%>的最外层最好要用单引号。
与数据库有关而且绑定到DataView,DataTable,DataSet 等数据源的数据绑定表达式都有那些?
1,<%#DataBind.Eval(Container.DataItem,"字段名")%> <%#DataBind.Eval(Container.DataItem,"字段名","{0:c}") %> 还有2种不常用的: <%# DataBinder.Eval(Container,"DataItem.字段名")%> <%# DataBinder.Eval(Container,"DataItem.字段名",{0:c})%> Container.DataItem相当于数据库中某个表或者视图中的一行记录,而一行可以有很多 列。 最后一个参数和 String.Format的形式一样。例如c代表货币,p代表百分号,d代表短日期 格式显示,f代表浮点数现实,f3代表小数点后三为,一次类推。
使用三目运算符?:的例子: <%# DataBinder.Eval(Container.DataItem, "字段名").ToString().Trim().Length> 16?DataBinder.Eval(Container.DataItem, "字段名 ").ToString().Trim().Substring(0,16):DataBinder.Eval(Container.DataItem, "字段名").ToString().Trim() %>
2,<%#Eval("字段名")%> <%#Eval("字段名","{0:c}")%> .NET 2.0新出现的一个方法。和DataBind.Eval()等价。
最后一个参数和 String.Format的形式一样。例如c代表货币,p代表百分号,d代表短日期格 式显示,f代表浮点数现实,f3代表小数点后三位,一次类推。
使用三目运算符的例子: <%#(Eval("性别")).ToString() =="True"?"男":"女"%>
性别字段类型为:是/否(Access),bit(sql server) 使用方法调用的例子: <%# GetUserPhoto(Eval("PhotoPath")) %> GetUserPhoto()的定义:
string
GetUserPhoto(
object
photoPath) {
if
(photoPath
==
DBNull.Value)
<%
#((DataRowView)Container.DataItem)[
"
字段名
"
]
%>
绑定到DataView,DataTable,DataSet {
return
"
<img src='Images/none.gif'>
"
; }
else
{
return
"
<img src='Upload/
"
+
photoPath.ToString()
+
"
'>
"
; } }
3, <%#((DataRowView)Container.DataItem)["字段名"] %> <%# string.Format("{0:c}", ((DataRowView)Container.DataItem)["字段名"])%> Container.DataItem相当于数据库中某个表或者视图中的一行记录,而一行可以有很多 列。 用String.Format方法设定字段的显示样式。例如c代表货币,p代表百分号,d代表短日期格 式显示,f代表浮点数现实,f3代表小数点后三为,一次类推。 类型转换例子:<%# (int)((DataRowView)Container.DataItem)["字段名1"]*(int) ((DataRowView)Container.DataItem)["字段名2"]%> 意思是2个字段相乘。 上 面三种绑定方法的效率:Eval方法执行时候会调用DataBinder.Eval方法,DataBinder.Eval 方法在运行时使用反射执行后期绑 定计算,会导致性能明显下降。所以会导致性能明显下降。所以 三者中<%#((DataRowView)Container.DataItem)[" 字段名"] %>的性能最好。
今天就先写到这里,实在太晚了,抽时间继续写XPath()。
Feedback
浅谈.NET中的数据绑定表达式(二) 这一节继续来谈.NET中的数据绑定表达式。
本节涉及的内容如下: 1,数据绑定方法的来源以及在低层上的实现。 2,数据绑定方法的执行效率排序。
<%
#Container.DataItem
%>
<%
#GetDataItem()
%>
<%
#
Eval
(
"
字段名
"
)
%>
<%
#DataBinder.Eval(Container.DataItem,
"
字段名
"
)
%>
<%
#((DataRowView)Container.DataItem)[
"
字段名
"
]
%>
<%
#((Type)Container.DataItem).成员
%>
<%
#((Type)GetDataItem()).成员
%>
上面七种绑定形式以及它们的变幻形式都用过吗?性能怎么排序?
复习一下:第一节我们主要谈了数据绑定表达式的各种形式,在ASP.NET页面中出现的位置,以及我们常绑定到与数据库有关的DataView,DataTable,DataSet 等数据源的数据绑定表达式的各种形式。
你有没有对Eval方法和DataBinder.Eval方法好奇过? 在.NET2.0中我们经常用Eval方法在Repeater,DataList,GridView等循环控件中绑定数据,Eval方法和DataBinder.Eval方法在低层是怎么实现的?它们到底有什么千丝万缕的关系?
一,来源、实现。 我 们常用的Eval方法其实是Page类的一个静态单向只读方法,而且它是一个受保护的方法。实际上Page类的Eval方法是继承自 TemplateControl类的。TemplateControl 类是一个抽象类,它为Page 类和 UserControl 类提供通用属性和方法。我们先来看一下继承家谱:
System.Object System.Web.UI.Control System.Web.UI.TemplateControl System.Web.UI.Page System.Web.UI.UserControl
Eval方法就是TemplateControl类的方法,它有两种形式:
名称 | 说明 |
---|
TemplateControl.Eval (String) | 计算数据绑定表达式。 | TemplateControl.Eval (String, String) | 使用用于显示结果的指定格式字符串计算数据绑定表达式。 | 事实上TemplateControl类还提供了XPath方法和XPathSelect方法供Page类和UserControl继承。这2个方法是和XML数据源有关的绑定方法。 如果细心的你查看TemplateControl类的基类Control类,你就会发现其实Control类并没有提供Eval,XPath,XPathSelect等方法。所以Eval,XPath等方法最终是在TemplateControl类中实现的。 现在,终于找到了Eval,XPath等数据绑定方法的来源了。 Eval,XPath等方法是.NET 2.0新增的方法。在.NET 1.1时代我们经常用的是DateBinder.Eval方法。形如:
<%#DataBind.Eval(Container.DataItem,"字段名") %>
<%#DataBind.Eval(Container.DataItem,"字段名","{0:c}") %>
Eval的出现其实就是为了简化DataBinder.Eval方法的写法从而代替它。 在ASP.NET 2.0中及以上,当我们调用Eval时,Eval 方法会使用GetDataItem方法调用DataBinder.Eval方法计算表达式的值。要想理解这句话,就算查边MSDN也一头雾水,除非我们知道Eval方法的源代码,否则根本找不到蛛丝马迹。这里就要用到反射了。我们通过反射获得了Eval方法的源代码:
protected internal object Eval(string expression) { this.CheckPageExists(); return DataBinder.Eval(this.Page.GetDataItem(), expression); }
终于见到GetDataItem()方法了,其实它就是Page类的 一个方法,也是.NET 2.0新增一个方法。GetDataItem()方法的作用是为了获得Container.DataItem,它是.NET 2.0中用来代替Container.DataItem的,如果你曾经用Repeater和DataList等绑定过数组或者ArrayList等,你就 会发现<%#GetDataItem()%>和<%#Container.DataItem%>等价。同时,可以肯定:Eval方法在低层上确实是调用DataBinder.Eval方法实现数据绑定的。其中“this.CheckPageExists();” 是检查调用的时候有没有Page对象的,如果没有则会抛出一个异常。
要弄清Eval是怎么工作的,GetDataItem()方法的低层实现我们也要用反射来获取:
public object GetDataItem() { if ((this._dataBindingContext == null) || (this._dataBindingContext.Count == 0)) { throw new InvalidOperationException(SR.GetString("Page_MissingDataBindingContext")); } return this._dataBindingContext.Peek(); }
我们从GatDataItem()方法中看到“return this._dataBindingContext.Peek();”很快就猜想_dataBindingContext是不是一个堆栈呢?事实它就是一个堆栈!通过反射查看源代码我们得出:_dataBindingContext是一个Stack类型对象。所以它有Peek方法。“return this._dataBindingContext.Peek(); ”正是把堆栈顶部的元素返回。而if语句是用来判断这个堆栈是否已经存在或者是否已经有元素存在,如果if不成立,就会抛出一个异常。
从上面的分析我们知道:_dataBindingContext堆栈的作用是通过GetDataItem()方法这个桥梁向Eval方法提供Container.DateItem。用逆向思维来理解上面这句话:Eval方法可以自动计算出Container.DataItem,原因就是从dataBindingContext 堆栈来获取Container.DataItem;这也就为什么Eval方法能够知道形如<%#Eval"字段名"%>中字段名隶属于哪个数 据项的属性的原因;同时我们也知道.NET 2.0中的Eval在本质上的实现并没有抛弃Container.DataItem,而Container.DataItem在2.0时代也没有消失。
那么_dataBindingContext这个保存Container.DataItem的堆栈是怎么建立的呢? 我 们很快就想到每次绑定控件时候最后那条语句是什么:this.控件ID.DataBind();对就是DataBind()方法,DataBind()方 法还有一个重载:DataBind(bool raiseOnDataBinding)。为_dataBindingContext这个堆栈压入元素和弹出元素的方法正是用DataBind(bool flag)这个重载方法实现的。 DataBind(bool raiseOnDataBinding)在低层的实现:
protected virtual void DataBind(bool raiseOnDataBinding) { bool flag1 = false;//这个标志的用处在上下文中很容易推出来,如果有DataItem压栈,则在后面出栈。 if (this.IsBindingContainer)//判断控件是不是数据绑定容器,实际上就是判断控件类是不是实现了INamingContainer { bool flag2; object obj1 = DataBinder.GetDataItem(this, out flag2);//这个方法是判断控件是不是有DataItem属性,并把它取出来。 if (flag2 && (this.Page != null))//如果控件有DataItem { this.Page.PushDataBindingContext(obj1);//把DataItem压栈,PushDataBindingContext就是调用_dataBindingContext的Push方法 flag1 = true; } } try { if (raiseOnDataBinding)//这里是判断是不是触发DataBinding事件的。 { this.OnDataBinding(EventArgs.Empty); } this.DataBindChildren();//对子控件进行数据绑定,如果这个控件有DataItem,则上面会将DataItem压入栈顶,这样,在子控件里面调用Eval或者GetDataItem方法,就会把刚刚压进去的DataItem给取出来。 } finally { if (flag1)//如果刚才有压栈,则现在弹出来。 { this.Page.PopDataBindingContext();//PopDataBindingContext就是调用_dataBindingContext的Pop方法 } } }
当我们执行到this.控件ID.DataBind();时候。在低层上就会调用这个重载的方法来准备包含DataItem的_DatBindingContext堆栈。 上面的代码中提到了DataBinding事件,那么它一般什么时候被触发呢? 1,如果用编程方式,那么在我们调用DataBind()方法时候自动触发DataBinding事件。 2,如果我们用数据源控件(例如SqlDataSource等),当把控件绑定到数据源控件时候,这个事件就会自动触发。 一般数据绑定表达式常常放在模板中循环显示数据,例如Repeater和DataList等的模板。那么下面这个知识点应该知道:Repeater,DataList,FormView等控件必须使用模板,如果不使用模板,这些控件将无法显示数据。而GridView,DetailsView,Menu等控件也支持模板,但显示数据时不是必须的。而TreeView控件不支持模板。 注意:一般情况下,数据绑定表达式不会自动计算它的值,除非它所在的页或者控件显示调用DataBind()方法。DataBind()方法能够将数据源绑定到被调用的服务器控件及其所有子控件,同时分析并计算数据绑定表达式的值。 终于写的有点眉目了,好累!我们该回头看看Eval方法调用的静态DataBinder.Eval方法在低层的实现了。我把DataBinder类的源代码贴出来:
namespace
System.Web.UI {
using
System;
using
System.Collections;
using
System.ComponentModel;
using
System.Globalization;
using
System.Reflection;
using
System.Security.Permissions;
using
System.Web;
[PermissionSet(SecurityAction.LinkDemand, XML
=
"
<PermissionSet class="
"
System.Security.PermissionSet"
"
"r"n version="
"
1
"
"
>"r"n <IPermission class="
"
System.Web.AspNetHostingPermission, System, Version
=
1.0
.
5000.0
, Culture
=
neutral, PublicKeyToken
=
b77a5c561934e089"
"
"r"n version="
"
1
"
"
"r"n Level="
"
Minimal"
"
/>"r"n</PermissionSet>"r"n
"
)]
public
sealed
class
DataBinder {
private
static
readonly
char
[] expressionPartSeparator
=
new
char
[] {
'
.
'
};
private
static
readonly
char
[] indexExprEndChars
=
new
char
[] {
'
]
'
,
'
)
'
};
private
static
readonly
char
[] indexExprStartChars
=
new
char
[] {
'
[
'
,
'
(
'
};
public
static
object
Eval(
object
container,
string
expression) {
if
(expression
==
null
) {
throw
new
ArgumentNullException(
"
expression
"
); }
if
(container
==
null
) {
return
null
; }
string
[] expressionParts
=
expression.Trim().Split(expressionPartSeparator);
return
Eval(container, expressionParts); }
private
static
object
Eval(
object
container,
string
[] expressionParts) {
object
propertyValue
=
container;
for
(
int
i
=
0
; (i
<
expressionParts.Length)
&&
(propertyValue
!=
null
); i
++
) {
string
propName
=
expressionParts[i];
if
(propName.IndexOfAny(indexExprStartChars)
<
0
) { propertyValue
=
GetPropertyValue(propertyValue, propName); }
else
{ propertyValue
=
GetIndexedPropertyValue(propertyValue, propName); } }
return
propertyValue; }
public
static
string
Eval(
object
container,
string
expression,
string
format) {
object
obj2
=
Eval(container, expression);
if
((obj2
==
null
)
||
(obj2
==
DBNull.Value)) {
return
string
.Empty; }
if
((format
!=
null
)
&&
(format.Length
!=
0
)) {
return
string
.Format(format, obj2); }
return
obj2.ToString(); }
public
static
object
GetIndexedPropertyValue(
object
container,
string
expr) {
if
(container
==
null
) {
throw
new
ArgumentNullException(
"
container
"
); }
if
((expr
==
null
)
||
(expr.Length
==
0
)) {
throw
new
ArgumentNullException(
"
expr
"
); }
object
obj2
=
null
;
bool
flag
=
false
;
int
length
=
expr.IndexOfAny(indexExprStartChars);
int
num2
=
expr.IndexOfAny(indexExprEndChars, length
+
1
);
if
(((length
<
0
)
||
(num2
<
0
))
||
(num2
==
(length
+
1
))) {
throw
new
ArgumentException(HttpRuntime.FormatResourceString(
"
DataBinder_Invalid_Indexed_Expr
"
, expr)); }
string
propName
=
null
;
object
obj3
=
null
;
string
s
=
expr.Substring(length
+
1
, (num2
-
length)
-
1
).Trim();
if
(length
!=
0
) { propName
=
expr.Substring(
0
, length); }
if
(s.Length
!=
0
) {
if
(((s[
0
]
==
'
"
'
)
&&
(s[s.Length
-
1
]
==
'
"
'
))
||
((s[
0
]
==
'
"
''
) && (s[s.Length - 1] ==
'
"
''
))) { obj3
=
s.Substring(
1
, s.Length
-
2
); }
else
if
(
char
.IsDigit(s[
0
])) {
try
{ obj3
=
int
.Parse(s, CultureInfo.InvariantCulture); flag
=
true
; }
catch
(Exception) { obj3
=
s; } }
else
{ obj3
=
s; } }
if
(obj3
==
null
) {
throw
new
ArgumentException(HttpRuntime.FormatResourceString(
"
DataBinder_Invalid_Indexed_Expr
"
, expr)); }
object
propertyValue
=
null
;
if
((propName
!=
null
)
&&
(propName.Length
!=
0
)) { propertyValue
=
GetPropertyValue(container, propName); }
else
{ propertyValue
=
container; }
if
(propertyValue
==
null
) {
return
obj2; }
if
((propertyValue
is
Array)
&&
flag) {
return
((
object
[]) propertyValue)[(
int
) obj3]; }
if
((propertyValue
is
IList)
&&
flag) {
return
((IList) propertyValue)[(
int
) obj3]; } PropertyInfo info
=
propertyValue.GetType().GetProperty(
"
Item
"
, BindingFlags.Public
|
BindingFlags.Instance,
null
,
null
,
new
Type[] { obj3.GetType() },
null
);
if
(info
==
null
) {
throw
new
ArgumentException(HttpRuntime.FormatResourceString(
"
DataBinder_No_Indexed_Accessor
"
, propertyValue.GetType().FullName)); }
return
info.GetValue(propertyValue,
new
object
[] { obj3 }); }
public
static
string
GetIndexedPropertyValue(
object
container,
string
propName,
string
format) {
object
indexedPropertyValue
=
GetIndexedPropertyValue(container, propName);
if
((indexedPropertyValue
==
null
)
||
(indexedPropertyValue
==
DBNull.Value)) {
return
string
.Empty; }
if
((format
!=
null
)
&&
(format.Length
!=
0
)) {
return
string
.Format(format, indexedPropertyValue); }
return
indexedPropertyValue.ToString(); }
public
static
object
GetPropertyValue(
object
container,
string
propName) {
if
(container
==
null
) {
throw
new
ArgumentNullException(
"
container
"
); }
if
((propName
==
null
)
||
(propName.Length
==
0
)) {
throw
new
ArgumentNullException(
"
propName
"
); } PropertyDescriptor descriptor
=
TypeDescriptor.GetProperties(container).Find(propName,
true
);
if
(descriptor
==
null
) {
throw
new
HttpException(HttpRuntime.FormatResourceString(
"
DataBinder_Prop_Not_Found
"
, container.GetType().FullName, propName)); }
return
descriptor.GetValue(container); }
public
static
string
GetPropertyValue(
object
container,
string
propName,
string
format) {
object
propertyValue
=
GetPropertyValue(container, propName);
if
((propertyValue
==
null
)
||
(propertyValue
==
DBNull.Value)) {
return
string
.Empty; }
if
((format
!=
null
)
&&
(format.Length
!=
0
)) {
return
string
.Format(format, propertyValue); }
return
propertyValue.ToString(); } } }
二,执行效率
从“一”讲述的低层实现。我们很容易来排序下面数据绑定表达式的执行效率
<%
#Container.DataItem
%>
<%
#GetDataItem()
%>
<%
#
Eval
(
"
字段名
"
)
%>
<%
#DataBinder.Eval(Container.DataItem,
"
字段名
"
)
%>
<%
#((DataRowView)Container.DataItem)[
"
字段名
"
]
%>
<%
#((Type)Container.DataItem).成员
%>
<%
#((Type)GetDataItem()).成员
%>
1,效率最高应该是:
<%#((Type)Container.DataItem).成员 %>
<%#Container.DataItem%>
<%#((DataRowView)Container.DataItem)["字段名"] %>
2,效率排第二的是:
<%#((Type)GetDataItem()).成员 %>
<%#GetDataItem()%>
3,效率最低的是:
<%#Eval("字段名")%>
<%#DataBinder.Eval(Container.DataItem,"字段名")%>
其实按上面的排序有失公允,原因是这七种数据表达绑定形式运用的场合不是完全相同的。
使用场合大概如下: 1, <%#Eval("字段名")%> <%#DataBinder.Eval(Container.DataItem,"字段名")%> 它 们的使用场合最广,数据源可以为与数据库有关的DataSet,DataTable,DataView。也可以为普通集合(例如:数组, ArrayList,HashTable等)和泛行集合(例如:List<T>,Dictionary<Tkey, Tvalue>等)。 注:它们2个永远可以相互替换,至少目前是这样,凡是可以用Eval方法的地方,就可以用 DataBinder.Eval方法替换。从低层实现上,Eval比DataBinder.Eval方法效率稍低,原因是Eval方法对了调用 GetDataItem()方法这一步。但最终都是通过DataBinder.Eval方法利用反射技术根据名称查找属性,从而计算出表达式的值,所以非 常影响性能。 2, <%#((DataRowView)Container.DataItem)["字段名"] %> 它只能使用在数据源为与数据库有关的Dataset,DatTable,DataView。这些数据源都实现了IListSource接口。其实从低层实现本质上来看,它和<%#((Type)Container.DataItem).成员 %>类似。
3, <%#Container.DataItem%> <%#GetDataItem()%> <%#((Type)Container.DataItem).成员 %> <%#((Type)GetDataItem()).成员 %> 这 几种形式估计大家最不常用。它们一般只使用与普通集合(例如:数组,ArrayList,HashTable)和泛行集合(例如:List< T>,Dictionary<Tkey,Tvalue>)。其实本质上就是实现了IList,ICollection, IEnumerable,IDictionary等以及这些接口对应的泛行接口的集合。IList接口和IDictionary接口的区别是,一个只有 值,而另一个是键/值对,对应泛行形式也是这样。而Array就对用List<T>,而HashTable就对应 Dictionary<Tkey,Tvalue>。
|