【转】浅谈.NET中的数据绑定表达式1

数据绑定表达式必须包含在<%#和%>字符之间。格式如下:

<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,DateBinder.Eval取得的数据表的字段,这个是最常见的了,不再举例。

注意:如果数据绑定表达式作为属性的值,只要数据绑定表达式中没有出现双引号,那么<%#数据绑定表达式%>的最外层用双引号或者单引号都可以。如果数据绑定表达式中出现双引号,则<%#数据绑定表达式%>的最外层最好要用单引号。

与数据库有关而且绑定到DataView,DataTable,DataSet 等数据源的数据绑定表达式都有那些?

1,<%#DataBinder.Eval(Container.DataItem,"字段名")%>
      <%#DataBinder.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新出现的一个方法。和DataBinder.Eval()等价。
     最后一个参数和

String.Format的形式一样。例如c代表货币,p代表百分号,d代表短日期格式显示,f代表浮点数现实,f3代表小数点后三位,一次类推。

              <%#string.Format("{0:yyyy-MM-dd dddd}",Eval("stuBirth"))%>
            <%# DataBinder.Eval(Container.DataItem,"stuBirth","{0:yyyy-MM-dd}")%>
    

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)["字段名"] %>的性能最好。

这一节继续来谈.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类的源代码贴出来:

时间: 2024-10-29 10:01:16

【转】浅谈.NET中的数据绑定表达式1的相关文章

浅谈JS中逗号运算符的用法_javascript技巧

注意: 一.由于目前正在功读JavaScript技术,所以这里拿JavaScript为例.你可以自己在PHP中试试. 二.JavaScript语法比较复杂,因此拿JavaScript做举例. 最近重新阅读JavaScript权威指南这本书,应该说很认真的阅读,于是便想把所学的东西多记录下来.后 面本人将逐步写上更多关于本书的文章. 本文的理论知识来自于JavaScript权威指南,我这里做一下整理,或者说叫笔记. 如果你的基础够好的话,完全理解不成问题,但是如果读得有些郁闷的话,可以加我的QQ:

浅谈JavaScript中的分支结构_javascript技巧

说到JavaScript中的分支结构,我们就不得不提到流程控制这个词,我们所有的程序都是由数据和算法组成的. 程序=数据+算法 通常我们所说的算法都可以通过"顺序","分支","循环"三种结构来组合完成. 在ECMA中规定了一些语句(也称为流程控制语句,分支结构语句),从本质上来说,这些语句定义了ECMAScript中的主要语法,语句通常使用一个或者多个关键字来完成给定任务. 1.1 if 语句 if 语句 - 只有当指定条件为 true 时,使

浅谈javascript中关于日期和时间的基础知识_基础知识

前面的话 在介绍Date对象之前,首先要先了解关于日期和时间的一些知识.比如,闰年.UTC等等.深入了解这些,有助于更好地理解javascript中的Date对象.本文将介绍javascript关于日期和时间的基础知识 标准时间一般而言的标准时间是指GMT和UTC,以前是GMT,现在是UTC GMT 格林尼治标准时间(GMT)是指位于伦敦郊区的皇家格林尼治天文台的标准时间,因为本初子午线被定义在通过那里的经线 理论上来说,格林尼治标准时间的正午是指当太阳横穿格林尼治子午线时(也就是在格林尼治上空

浅谈php中的循环while、do...while、for、foreach四种循环_php实例

php中的while循环,循环执行代码块制定的次数,或者当指定的条件为真时循环执行代码块. ------------------------------------------------------------- 在我们编写代码是时候,我们经常需要一块代码块重复执行多次.我们就可以使用while循环语句来完成这个任务. while--只要指定条件成立,则循环执行代码块. do...while--首先执行一次代码块,然后在指定的条件成立时重复这个循环. for--循环执行代码块制定的次数. fo

浅谈Angular中ngModel的$render_AngularJS

在我开始着手ngModel的领域时候,有一个问题很令我纠结,那就是$render()到底是做什么的呢?查了很多资料都只是简单的描述一下,这就令我很纠结了,终于在一个阳光明媚的晚上,我终于解决了这个大问题 那么这个$render方法到底是干什么的呢?他的用处就是在$viewValue改变的时候可以重新绑定model数据,但是我们要注意一点($viewValue和DOM节点的value是不同的),我觉得他们的区别有点类似setTimeout和$timeout的区别,但是又不太一样.ps:其实mode

浅谈JavaScript中数组的增删改查_javascript技巧

数组的增加 •ary.push()   向数组末尾添加元素,返回的是添加后新数组的长度,原有数组改变 •ary.unshift()  向数组开头添加元素,返回的是添加后新数组的长度,原有数组改变 • var ary=[1,2,3,4];   var res=ary.unshift(6);   console.log(res); ---->5   返回的是新数组的长度•ary.splice(n,m,x)从索引n开始删除m个元素,把新增的元素X放在索引n的前面,把删除的元素当成一个新数组返回,原有数

浅谈Python中copy()方法的使用

  这篇文章主要介绍了浅谈Python中copy()方法的使用,Python中的拷贝分为潜拷贝和深拷贝,本文只是简单介绍用法,需要的朋友可以参考下 copy()方法返回字典的浅拷贝. 语法 以下是copy()方法的语法: ? 1 dict.copy() 参数 NA 返回值 此方法返回字典的浅拷贝. 例子 下面的例子显示了copy()方法的使用. ? 1 2 3 4 5 6 #!/usr/bin/python   dict1 = {'Name': 'Zara', 'Age': 7};   dict

浅谈ASP中Request对象获取客户端数据的顺序

request|对象|客户端|数据 浅谈ASP中Request对象获取客户端数据的顺序 /**描述:在使用ASP Request对象时需要注意的小问题作者:慈勤强Email : cqq1978@yeah.net**/ 在ASP中Request对象是获取客户端提交数据的一个很重要的对象,大家对他也是非常熟悉了.虽然如此,还是经常有人问我下面的几种写法有什么不同,到底应该怎么写?strMessage = Request("msg")strMessage = Request.Form(&qu

浅谈jquery中delegate()与live()

  这篇文章主要介绍了浅谈jquery中delegate()与live()的相关资料,需要的朋友可以参考下 delegate() 方法为指定的元素(属于被选元素的子元素)添加一个或多个事件处理程序 例如给id是showspan的div中的span标签添加事件 ? 1 2 3 4 5 6 7 8 9 10 <div id="showspan"><span>showspan**showspan</span></div> <span>