日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

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

發布時間:2025/6/16 asp.net 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据绑定表达式(下):.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的,如果你曾經用RepeaterDataList等綁定過數組或者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方法?!皉eturn ? 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://down.51cto.com/data/2352395











本文轉自terryli51CTO博客,原文鏈接:http://blog.51cto.com/terryli/150594?,如需轉載請自行聯系原作者



總結

以上是生活随笔為你收集整理的数据绑定表达式(下):.NET发现之旅(二)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。