數據綁定表達式(上):.NET發現之旅(一) javascript
2009-06-30 10:29:06 來源:網絡轉載 做者:佚名 共有評論(0)條 瀏覽次數:859php
做爲.NET平臺軟件開發者,咱們頻繁與各類各樣的數據交互,這些數據經常來源於文本、自定義類型、XML、數據庫等,訪問這些數據有不少方法,而數據綁定表達式即是其中最經常使用也是最實用的方法之一。我用2篇博文,儘可能說透。NET平臺數據綁定表達的來源,使用方法,底層原理,效率等。另外這2篇博文我最初發表於博客園。html
數據綁定表達式必須包含在<%#和%>字符之間。格式以下:java
<tagprefix:tagname property='<%# data-binding expression %>' runat="server" />sql |
或者以下:數據庫
<%# data-binding expression %>express |
ASP.NET 支持分層數據綁定模型,數據綁定表達式使用 Eval 和 Bind 方法將數據綁定到控件,並將更改提交回數據庫。編程
Eval 方法是靜態單向(只讀)方法,因此Eval 函數用於單向(只讀)綁定,該方法採用數據字段的值做爲參數並將其做爲字符串返回。c#
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取得的數據表的字段,這個是最多見的了,再也不舉例。
注意:若是數據綁定表達式做爲屬性的值,只要數據綁定表達式中沒有出現雙引號,那麼<%#數據綁定表達式%>的最外層用雙引號或者單引號均可以。若是數據綁定表達式中出現雙引號,則<%#數據綁定表達式%>的最外層最好要用單引號。
,<%#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中的數據綁定表達式。
本節涉及的內容以下:
一,數據綁定方法的來源以及在低層上的實現。
二,數據綁定方法的執行效率排序。
<%#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>.
轉自 http://www.rjgc.net/control/content/content.php?nid=11386
做爲.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取得的數據表的字段,這個是最多見的了,再也不舉例。
注意:若是數據綁定表達式做爲屬性的值,只要數據綁定表達式中沒有出現雙引號,那麼<%#數據綁定表達式%>的最外層用雙引號或者單引號均可以。若是數據綁定表達式中出現雙引號,則<%#數據綁定表達式%>的最外層最好要用單引號。
,<%#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中的數據綁定表達式。
本節涉及的內容以下:
一,數據綁定方法的來源以及在低層上的實現。
二,數據綁定方法的執行效率排序。
<%#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>.
轉自 http://www.rjgc.net/control/content/content.php?nid=11386