數據綁定表達式(上):.NET發現之旅(一)

數據綁定表達式(上):.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>

123

 

 

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() + "'>";

    }

    }

123

 

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

 

轉自 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>

123

 

 

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() + "'>";

    }

    }

123

 

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

 

轉自 http://www.rjgc.net/control/content/content.php?nid=11386

相關文章
相關標籤/搜索