数据绑定表达式
数据绑定表达式(上):.NET发现之旅(一) 2009-06-30 10:29:06 来源:网络转载 作者:佚名 共有评论(0)条 浏览次数:859 作为.NET平台软件开发者,我们频繁与各种各样的数据交互,这些数据常常来源于文本、自定义类型、XML、数据库等,访问这些数据有很多方法,而数据绑定表达式便是其中最常用也是最实用的方法之一。我用2篇博文,尽量说透。NET平台数据绑定表达的来源,使用方法,底层原理,效率等。另外这2篇博文我最初发表于博客园。 一,概要数据绑定表达式必须包含在<%#和%>字符之间。格式如下:
或者如下:
ASP.NET 支持分层数据绑定模型,数据绑定表达式使用 Eval 和 Bind 方法将数据绑定到控件,并将更改提交回数据库。 Eval 方法是静态单向(只读)方法,所以Eval 函数用于单向(只读)绑定,该方法采用数据字段的值作为参数并将其作为字符串返回。 Bind 方法支持读/写功能,所以Bind 函数用于双向(可更新)绑定。该方法可以检索数据绑定控件的值并将任何更改提交回数据库。 XPath 方法支持对XML类型的数据源提供支持。 二,数据绑定表达式出现的位置1,可以将数据绑定表达式包含在服务器控件或者普通的html元素的开始标记中属性名/属性值对的值侧。例如:
此时数据的绑顶表达式可以是一个变量,也可以是一个带返回值的c#或者VB.NET方法,还可以是某个控件的某个属性的值,也可以是c#或者VB.NET对象的某个字段或者属性的值等等。当然也可以直接就是一个字符串,例如"hello".
此时数据的绑顶表达式可以是一个变量,也可以是一个带返回值的C#或者VB.NET方法,还可以是某个控件的某个属性的值,也可以是C#或者VB.NET对象的某个字段或者属性的值等等。当然也可以直接就是一个字符串,例如"hello". 如果此时的数据绑定表达式是Eval("数据库中某个表的某个字段")等,那么必须把<%#Eval("数据绑定表达式1")%> <%#Eval("数据绑定表达式2")%> 放在像Repeater,DataList,GridView这样的控件的模板中。 3,可以将数据绑定表达式包含在Javascript代码中,从而实现在Javascript中调用C#或者VB.NET的方法。例如:
123
三,数据绑定表达可以是什么类型?1,可以是一个变量 例如
2,可以是服务器控件的属性值 例如: <asp:Label ID="Label1" runat="server" Text="<%#TextBox2.Text %>"></asp:Label> 3,可以是一个数组等集合对象 例如把一个数组绑定到列表控件,例如ListBox等,或者Repeater,DataList,GridView这样的控件等,此时只需要把属性DataSource='<%# 数组名%>' . 4,可以是一个表达式 例如:Person是一个对象,Name和City是它的2个属性,则数据绑定表达式可以这样写: 5,可以是一个方法 例如:<%#GetUserName()%>.GetUserName()是一个已经定义的C#方法,一般要求有返回值。 6,可以是用Eval,DateBinder.Eval取得的数据表的字段,这个是最常见的了,不再举例。 注意:如果数据绑定表达式作为属性的值,只要数据绑定表达式中没有出现双引号,那么<%#数据绑定表达式%>的最外层用双引号或者单引号都可以。如果数据绑定表达式中出现双引号,则<%#数据绑定表达式%>的最外层最好要用单引号。 四,与数据库有关而且绑定到DataView,DataTable,DataSet 等数据源的数据绑定表达式都有那些?
还有2种不常用的:
Container.DataItem相当于数据库中某个表或者视图中的一行记录,而一行可以有很多列。 使用三目运算符?:的例子:
2,<%#Eval("字段名")%> <%#Eval("字段名","{0:c}")%> .NET 2.0新出现的一个方法。和DataBinder.Eval()等价。 绑定生日的例子:
使用三目运算符的例子: <%#(Eval("性别"))。ToString() =="True"?"男":"女"%> 性别字段类型为:是/否(Access),bit(sql server) 调用方法的例子:
123
3, <%#((DataRowView)Container.DataItem)["字段名"] %>
Container.DataItem相当于数据库中某个表或者视图中的一行记录,而一行可以有很多列。 类型转换后相乘的例子:
上面三种绑定方法的效率:Eval方法执行时候会调用DataBinder.Eval方法,DataBinder.Eval方法在运行时使用反射执行后期绑定计算,会导致性能明显下降。所以会导致性能明显下降。所以三者中<%#((DataRowView)Container.DataItem)["字段名"] %>的性能最好。
数据绑定表达式(下):.NET发现之旅(二)这一节继续来谈。NET中的数据绑定表达式。 本节涉及的内容如下: 一,数据绑定方法的来源以及在低层上的实现。 二,数据绑定方法的执行效率排序。 <%#Container.DataItem%> 复习一下:第一节我们主要谈了数据绑定表达式的各种形式,在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
事实上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) 上面的代码中提到了DataBinding事件,那么它一般什么时候被触发呢? 1,如果用编程方式,那么在我们调用DataBind()方法时候自动触发DataBinding事件。 2,如果我们用数据源控件(例如SqlDataSource等),当把控件绑定到数据源控件时候,这个事件就会自动触发。 一般数据绑定表达式常常放在模板中循环显示数据,例如Repeater和DataList等的模板。那么下面这个知识点应该知道:Repeater,DataList,FormView等控件必须使用模板,如果不使用模板,这些控件将无法显示数据。而GridView,DetailsView,Menu等控件也支持模板,但显示数据时不是必须的。而TreeView控件不支持模板。 注意:一般情况下,数据绑定表达式不会自动计算它的值,除非它所在的页或者控件显示调用DataBind()方法。DataBind()方法能够将数据源绑定到被调用的服务器控件及其所有子控件,同时分析并计算数据绑定表达式的值。 终于写的有点眉目了,好累!我们该回头看看Eval方法调用的静态DataBinder.Eval方法在低层的实现了。我把DataBinder类的源代码作为附近提供下载。
二,执行效率 从“一”讲述的低层实现。我们很容易来排序下面数据绑定表达式的执行效率 使用场合大概如下: 1, 注:它们2个永远可以相互替换,至少目前是这样,凡是可以用Eval方法的地方,就可以用DataBinder.Eval方法替换。从低层实现上,Eval比DataBinder.Eval方法效率稍低,原因是Eval方法对了调用GetDataItem()方法这一步。但最终都是通过DataBinder.Eval方法利用反射技术根据名称查找属性,从而计算出表达式的值,所以非常影响性能。 2, <%#((DataRowView)Container.DataItem)["字段名"] %> 它只能使用在数据源为与数据库有关的Dataset,DatTable,DataView.这些数据源都实现了IListSource接口。其实从低层实现本质上来看,它和<%#((Type)Container.DataItem)。成员 %>类似。 3,
转自http://www.rjgc.net/control/content/content.php?nid=11386 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |