XSLT存档  

不及格的程序员-八神

 查看分类:  ASP.NET XML/XSLT JavaScripT   我的MSN空间Blog

2 Answers

This article might help you understand. Quote:

So what is this expression exactly? The <%# %> means this is a DataBinding expression and Container.DataItem is an alias for the current item in the datasource. In other words, if you are binding to a collection of objects Container.DataItem is the current row of that collection.

This blog entry gives help on when to use. Quote:

Container.DataItem is a runtime alias for the DataItem for this specific item in the bound list. For a grid which displays 10 rows of data, this is one row from the datasource. The actual type of DataItem is determined by the type of the datasource. For example, if the datasource is a Dataview, the type of DataItem is DataRowView. If the type of the datasource is an array of strings, the type of DataItem is String. If the datasource is a collection of strongly-typed objects (for example "Employees" objects), the type of DataItem is Employees. 

Each of these cases requires a slightly different databinding expression, with further differences between VB and C#.

 
    
what does the current item in the datasource exactly mean? – sly_Chandan Oct 22 '10 at 17:20
2  
@chandan - Well, if its an array of string {'a','b','c'}, then currentitem is the one which is currently processing. It could be a,b or c at that point of time. Does this answer your question? – Sachin Shanbhag Oct 22 '10 at 17:25 
    
do you mean the current item which is being processed at runtime to bind a particular dataitem from a datasource. – sly_Chandan Oct 22 '10 at 17:31
    
@Chandan - yes exactly. – Sachin Shanbhag Oct 22 '10 at 17:36
    
thank you so much Sachin – sly_Chandan Oct 22 '10 at 17:36

I ran across this same question specifically in the context of trying to access Container.DataItemfrom within the code-behind. Container exists in the aspx/ascx code but does not exist within the code-behind. By looking at the generated C# code, I saw that it's a casted reference to BindingContainer on the specific control being bound.

Equivalent code-behind code for Container.DataItem is this:

var ddl = (DropDownList) source;
var dataItem = ((RepeaterItem) ddl.BindingContainer).DataItem;
 

 

在使用asp.net服务器端控件的时候,想要动态绑定控件某属性的值,或者动态绑定控件事件方法的参数,例如一个<asp:RadioButton ID="RadioButton5" GroupName="option" Text="<%#Eval("Answer")%>" runat="server"/> 绑定Text属性的值,这样运行是有错误的,服务器标记的格式不正确。
解决方法1:可以把服务器控件换为Html的radio这样就不会有问题了,如果用html的控件也出现这个问题,看看是不是加了runat="server",去掉就OK了。

解决方法2:如果必须用服务器端控件的话,需要把"<%#Eval("Answer")%>" 的双引号改为单引号'<%#Eval("Answer")%>' 外侧单引号,里面双引号就不会出错了。

还有一种情况可能引号嵌套几层,这样运行也会出现错误或者直接不识别<%#Eval("Answer")%>' 标记,例如<asp:RadioButton ID="RadioButton5" GroupName="option" runat="server" onclick='getScore("<%#Eval("Answer")%>")'/>,在控件的onclick添加一个js方法getScore需要传递一个参数,参数我们想通过后台动态绑定,这样虽然不会报错,但是查看源码之后发现<%标记没有识别,我们可以通过string.Format方法来解决如下:<asp:RadioButton ID="RadioButton5" GroupName="option" runat="server" onclick='<%#string.Format("getScore(\"{0}\",\"{1}\")",Eval("Answer"),"A") %>'/>,我们把需要转义的符号转义一下,最后就得到我们想要的结果了。

 


 

 

一直没有深入研究过asp.net的数据绑定,今天看到一篇文章,感觉豁然开朗.

文章原地址:http://blog.csdn.net/Joetao/article/details/5051734

数据绑定表达式(上):.NET发现之旅(一)

2009-06-30 10:29:06 来源:网络转载 作者:佚名 共有评论(0)条 浏览次数:859

  作为.NET平台软件开发者,我们频繁与各种各样的数据交互,这些数据常常来源于文本、自定义类型、XML、数据库等,访问这些数据有很多方法,而数据绑定表达式便是其中最常用也是最实用的方法之一。我用2篇博文,尽量说透。NET平台数据绑定表达的来源,使用方法,底层原理,效率等。另外这2篇博文我最初发表于博客园。

   一,概要

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

 <tagprefix:tagname property='<%# data-binding expression %>' runat="server" />

  或者如下:

<%# data-binding expression %>

     ASP.NET 支持分层数据绑定模型,数据绑定表达式使用 Eval 和 Bind 方法将数据绑定到控件,并将更改提交回数据库。

     Eval 方法是静态单向(只读)方法,所以Eval 函数用于单向(只读)绑定,该方法采用数据字段的值作为参数并将其作为字符串返回。

     Bind 方法支持读/写功能,所以Bind 函数用于双向(可更新)绑定。该方法可以检索数据绑定控件的值并将任何更改提交回数据库。

     XPath 方法支持对XML类型的数据源提供支持。

     二,数据绑定表达式出现的位置

     1,可以将数据绑定表达式包含在服务器控件或者普通的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这样的控件的模板中。
  2,数据绑定绑定表达式包含在在页面中的任何位置。例如:

复制代码
 <form id="form1" runat="server">

<div>

<%#Eval("数据绑定表达式1")%>

<%#Eval("数据绑定表达式2")%>

</div>

</form>
复制代码
  此时数据的绑顶表达式可以是一个变量,也可以是一个带返回值的C#或者VB.NET方法,还可以是某个控件的某个属性的值,也可以是C#或者VB.NET对象的某个字段或者属性的值等等。当然也可以直接就是一个字符串,例如"hello".

     如果此时的数据绑定表达式是Eval("数据库中某个表的某个字段")等,那么必须把<%#Eval("数据绑定表达式1")%> <%#Eval("数据绑定表达式2")%>  放在像Repeater,DataList,GridView这样的控件的模板中。

     3,可以将数据绑定表达式包含在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 等数据源的数据绑定表达式都有那些?

<%#DataBinder.Eval(Container.DataItem,"字段名")%>

<%#DataBinder.Eval(Container.DataItem,"字段名","{0:c}")%>

     还有2种不常用的:

 <%# DataBinder.Eval(Container,"DataItem.字段名")%>

<%# DataBinder.Eval(Container,"DataItem.字段名",{0:c})%>

       Container.DataItem相当于数据库中某个表或者视图中的一行记录,而一行可以有很多列。

     使用三目运算符?:的例子:

 <%# 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("{0:yyyy-MM-dd dddd}",Eval("stuBirth"))%>

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

        使用三目运算符的例子:

     <%#(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相当于数据库中某个表或者视图中的一行记录,而一行可以有很多列。

     类型转换后相乘的例子:

<%# (int)((DataRowView)Container.DataItem)["字段名1"]*(int)
((DataRowView)Container.DataItem)["字段名2"]%>

        上面三种绑定方法的效率:Eval方法执行时候会调用DataBinder.Eval方法,DataBinder.Eval方法在运行时使用反射执行后期绑定计算,会导致性能明显下降。所以会导致性能明显下降。所以三者中<%#((DataRowView)Container.DataItem)["字段名"] %>的性能最好。

数据绑定表达式(下):.NET发现之旅(二)

这一节继续来谈。NET中的数据绑定表达式。

    本节涉及的内容如下:

    一,数据绑定方法的来源以及在低层上的实现。

    二,数据绑定方法的执行效率排序。

<%#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类的源代码作为附近提供下载

 

     二,执行效率

    从“一”讲述的低层实现。我们很容易来排序下面数据绑定表达式的执行效率

<%#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>.

最后想说的是,绑定数据表达式,可以是一个后台的方法,我们在这个方法里可以做各种想做的事,比如格式化某些数据,改变字体大小,颜色,改变单元格颜色等,这些是通过直接返回html标签做到的.比如:

复制代码
public string GetColor(object value) 
{
if (value.ToString() == "已打印")
{
return "<div style='"+value +"</div>";
}
else
{
return value.ToString();
}
}
复制代码

 

 

 

 

posted on 2017-10-09 22:08  不及格的程序员-八神  阅读(15)  评论(0编辑  收藏  举报