数据绑定表达式(下):.NET发现之旅(二)
本节涉及的内容如下:
一,数据绑定方法的来源以及在低层上的实现。
二,数据绑定方法的执行效率排序。
<%#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类的基类Control类,你就会发现其实Control类并没有提供Eval,XPath,XPathSelect等方法。所以Eval,XPath等方法最终是在TemplateControl类中实现的。
现在,终于找到了Eval,XPath等数据绑定方法的来源了。
Eval,XPath等方法是.NET 2.0新增的方法。在.NET 1.1时代我们经常用的是DateBinder.Eval方法。形如:
<%#DataBind.Eval(Container.DataItem,"字段名","{0:c}") %>
在ASP.NET 2.0中及以上,当我们调用Eval时,Eval 方法会使用GetDataItem方法调用DataBinder.Eval方法计算表达式的值。要想理解这句话,就算查边MSDN也一头雾水,除非我们知道Eval方法的源代码,否则根本找不到蛛丝马迹。这里就要用到反射了。我们通过反射获得了Eval方法的源代码:
{
this.CheckPageExists();
return DataBinder.Eval(this.Page.GetDataItem(), expression);
}
要弄清Eval是怎么工作的,GetDataItem()方法的低层实现我们也要用反射来获取:
{
if ((this._dataBindingContext == null) || (this._dataBindingContext.Count == 0))
{
throw new InvalidOperationException(SR.GetString("Page_MissingDataBindingContext"));
}
return this._dataBindingContext.Peek();
}
从上面的分析我们知道:_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)在低层的实现:
{
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类的源代码作为附近提供下载。
从“一”讲述的低层实现。我们很容易来排序下面数据绑定表达式的执行效率
<%#GetDataItem()%>
<%#Eval("字段名")%>
<%#DataBinder.Eval(Container.DataItem,"字段名")%>
<%#((DataRowView)Container.DataItem)["字段名"] %>
<%#((Type)Container.DataItem).成员 %>
<%#((Type)GetDataItem()).成员 %>
<%#Container.DataItem%>
<%#((DataRowView)Container.DataItem)["字段名"] %>
2,效率排第二的是:
<%#GetDataItem()%>
3,效率最低的是:
<%#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>。
附件:http://down.51cto.com/data/2352395
本文转自terryli51CTO博客,原文链接:http://blog.51cto.com/terryli/150594 ,如需转载请自行联系原作者
数据绑定表达式(下):.NET发现之旅(二)相关推荐
- MultiRow发现之旅(二)- 详解属性管理器
前文回顾 MultiRow发现之旅(一)- 高效模板设计器 属性管理器 上一篇提到MultiRow模板设计器中有一个"属性管理器",这里就聊一聊这个属性管理器.在MultiRow模 ...
- MultiRow发现之旅(六)- 使用MultiRow开发票据应用(附源码)
前文回顾 MultiRow发现之旅(一)- 高效模板设计器 MultiRow发现之旅(二)- 详解属性管理器 MultiRow发现之旅(三)- 模板管理器和Table MultiRow发现之旅(四)- ...
- C#发现之旅第十四讲 基于动态编译的VB.NET脚本引擎
本章说明 在前面章节中,笔者使用了反射和动态编译技术实现了快速ORM框架,在本章中笔者将继续使用这些技术来实现一个VB.NET的脚本引擎,使得人们在开发中能实现类似MS Office那样实现VBA宏的 ...
- C#发现之旅第二讲 C#-XSLT开发
C#发现之旅第二讲 C#-XSLT开发 袁永福 2008-5-15 系列课程说明 为了让大家更深入的了解和使用C#,我们开始这一系列的主题为"C#发现之旅"的技术讲座.考虑 ...
- WireShark黑客发现之旅—肉鸡邮件服务器
聚锋实验室 · 2015/07/06 10:45 0x00 背景 肉鸡也称傀儡机,是指可以被黑客远程控制的机器.一旦成为肉鸡,就可以被攻击者随意利用,如:窃取资料.再次发起攻击.破坏等等.下面将利用W ...
- C#发现之旅第一讲 C#-XML开发
C#发现之旅第一讲 C#-XML开发 袁永福 2008-5-15 系列课程说明 为了让大家更深入的了解和使用C#,我们将开始这一系列的主题为"C#发现之旅"的技术讲座.考虑 ...
- C#发现之旅第九讲 ASP.NET验证码技术
C#发现之旅第九讲 ASP.NET验证码技术 袁永福 2008-5-15 系列课程说明 为了让大家更深入的了解和使用C#,我们将开始这一系列的主题为"C#发现之旅"的技术讲 ...
- 笔记:数据绑定表达式(一)
数据绑定表达式必须包含在<%#和%>字符之间.格式如下: <tagprefix:tagname property='<%# data-binding expression %& ...
- HALCON学习之旅(二)
HALCON学习之旅(二) 文章目录 HALCON学习之旅(二) 1.HALCON用户界面操作符 2.HACLON基础语法 ①.运算符 ②.Tuple数组 ③.字符数字格式化 1.HALCON用户界面 ...
最新文章
- 常用[js,css,jquery,html]
- php中js代码放在哪,JavaScript
- 软件测试工具和报告学习-3月6日
- 一套完整的java程序_编写一个完整的Java Application 程序
- 【将图像字符画】【第二玩】图像字符化
- CS184.1X 计算机图形学导论 第8讲 学习笔记
- 使用caffemodel模型(由mnist训练)测试单张手写数字样本
- 【Elasticsearch】elasticsearch 段 segment 段合并
- 教你使用 IDEA 配置和运行vue项目
- linux查看native进程,Android 分析应用程序占用native内存
- [JavaScript] DOM
- ARM 和 RISC-V 公然开撕,GNOME 之父指责 ARM
- 大学计算机课程进制的转换教程,交大计算机课程(1):各种进制转换
- 关于各种校园网,局域网等出现IP识别错误(169IP开头)及其导致的联网失败,DNS错误的解决方法
- 2022-07-02 Android 进入app 后 距离传感器控制手机屏幕熄灭的方法-接近传感器Proximity Sensor的信号
- list去重和list倒叙
- 神州数码基础知识配置总结
- 禁止搜索引擎收录网站内容的几种方法
- 「GoTeam 招聘时间」ANKER Golang 开发工程师(深圳)
- mysql var和varp的区别_了解T-SQL stdev、stdevp、var和varp
热门文章
- DEV express 对Gridview某行的元素赋值
- ACM学习历程—UESTC 1226 Huatuo's Medicine(数学)(2015CCPC L)
- 【WP7】对象序列化
- [备忘]silverlight中关于“复制到输出目录”和“生成操作”
- SQL Server 找回没有备份的数据
- java实现Windows资源管理器
- java x86 模拟,Java模拟实现百度文档在线浏览
- Linux-鸟菜-7-Linux文件系统-EXT
- 【ijkplayer】编译 Android 版本的 ijkplayer ⑥ ( 进入 ijkplayer-android/android 目录 | 执行 compile-ijk.sh 脚本完成编译 )
- 【Google Play】Android 应用隐私政策 ( 生成隐私政策 | HTML 隐私政策模板 | Markdown 隐私政策模板 )