揭祕ASP.NET 2.0的Eval方法(轉)

實際上Eval方法是TemplateControl的,而System.Web.UI.Page和System.Web.UI.UserControl都繼承於TemplateControl,所以我們可以在Page和UserControl上直接調用個方法。  
   
  Page.Eval方法可以幫助我們更好的撰寫數據綁定表達式,在ASP.NET   1.x時代,數據綁定表達式的一般形式是:  
  <%#   DataBinder.Eval(   Container   ,   “DataItem.Name”)   %>  
  而在ASP.NET   2.0中,同樣的代碼,我們可以這樣寫:  
  <%#   Eval(   “Name”   )%>  
  ASP.NET   2.0是怎麼實現的呢?我們先從Eval方法來研究,通過反射.NET   work   2.0類庫的源代碼,我們可以看到這個方法是這樣實現的:  
  protected   internal   object   Eval(string   expression)  
  {  
              this.CheckPageExists();  
              return   DataBinder.Eval(this.Page.GetDataItem(),   expression);  
  }  
  第一行我們不必管,這是檢查調用的時候有沒有Page對象的,如果沒有則會拋出一個異常。  
  關鍵是第二行:  
              return   DataBinder.Eval(this.Page.GetDataItem(),   expression);  
  Page.GetDataItem()也是2.0中新增的一個方法,用途是正是取代ASP.NET   1.x中的Container.DataItem。  
  看來不摸清楚GetDataItem()方法,我們也很難明白Eval的原理。GetDataItem的實現也很簡單:  
  public   object   GetDataItem()  
  {  
              if   ((this._dataBindingContext   ==   null)   ||   (this._dataBindingContext.Count   ==   0))  
              {  
                          throw   new   InvalidOperationException(SR.GetString("Page_MissingDataBindingContext"));  
              }  
              return   this._dataBindingContext.Peek();  
  }  
  我們注意到了有一個內部對象_dataBindingContext,通過查源代碼發現這是一個Stack類型的東西。所以他有Peek方法。而這一段代碼很容易看懂,先判斷這個Stack是否被實例化,然後,判斷這個Stack裏面是不是有任何元素,如果Stack沒有被實例化或者沒有元素則拋出一個異常。最後是將這個堆棧頂部的元素返回。  
  ASP.NET   2.0用了一個Stack來保存所謂的DataItem,我們很快就查到了爲這個堆棧壓元素和彈出元素的方法:Control.DataBind方法:  
  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方法  
                          }  
              }  
  }  
  至此,我們已經可以完全瞭解ASP.NET   2.0中GetDataIten和Eval方法運作的原理了,下一次我打算研究ASP.NET   2.0中的新的Bind語法。  
   
   
  有提供Bind語法資料的和提出好建議的酌情給分,up、頂等分會很少,接分者無分。

關於效率:
毋庸置疑的是強類型轉換Container的效率是最高的,Eval最終是調用DataBinder.Eval方法,DataBinder.Eval是採用反射來獲取數據的,這顯然不如強類型數據轉換。  
   
  我們可以比較一下各種方法:  
   
  ((Type)   Container.DataItem).Property  
  這種方法效率是最高的,因爲不存在任何反射。  
   
  其次是:  
  ((Type)   GetDataItem()).Property  
  這種方法效率差的原因在於多了一個Stack的Peek操作,當然,實際上這點兒差別可以忽略。  
   
  最後是:  
  Eval或者DataBinder.Eval,這兩種方法都使用反射來查找屬性或者索引器成員,效率大打折扣。  
   
  另外一個值得注意的問題是,所有實現了INamingContainer接口的Control,都應該實現IDataItemContainer接口,因爲在Control.DataBind的時候,如果發現控件實現了INamingContainer接口,就會試圖去尋找它的DataItem,如果這個控件沒有實現IDataItemContainer,則DataBinder.GetDataItem方法會使用反射看看控件有沒有一個叫做DataItem的屬性成員,顯然這不是我們希望看到的。  
  其實ASP.NET還有一個標記接口:INonBindingContainer,實現了INamingContainer接口的控件可以選擇同時實現這個來命令ASP.NET不去尋找DataItem,可是很可惜,不知道微軟出於什麼目的,這個接口是internal的……  
   
  其實效率方面不必太重視了,Eval表達式很好看的,即使有那麼極端的重視效率,GeDataItem也是不錯的選擇。毋庸置疑的是強類型轉換Container的效率是最高的,Eval最終是調用DataBinder.Eval方法,DataBinder.Eval是採用反射來獲取數據的,這顯然不如強類型數據轉換。  
   
  我們可以比較一下各種方法:  
   
  ((Type)   Container.DataItem).Property  
  這種方法效率是最高的,因爲不存在任何反射。  
   
  其次是:  
  ((Type)   GetDataItem()).Property  
  這種方法效率差的原因在於多了一個Stack的Peek操作,當然,實際上這點兒差別可以忽略。  
   
  最後是:  
  Eval或者DataBinder.Eval,這兩種方法都使用反射來查找屬性或者索引器成員,效率大打折扣。  
   
  另外一個值得注意的問題是,所有實現了INamingContainer接口的Control,都應該實現IDataItemContainer接口,因爲在Control.DataBind的時候,如果發現控件實現了INamingContainer接口,就會試圖去尋找它的DataItem,如果這個控件沒有實現IDataItemContainer,則DataBinder.GetDataItem方法會使用反射看看控件有沒有一個叫做DataItem的屬性成員,顯然這不是我們希望看到的。  
  其實ASP.NET還有一個標記接口:INonBindingContainer,實現了INamingContainer接口的控件可以選擇同時實現這個來命令ASP.NET不去尋找DataItem,可是很可惜,不知道微軟出於什麼目的,這個接口是internal的……  
   
  其實效率方面不必太重視了,Eval表達式很好看的,即使有那麼極端的重視效率,GeDataItem也是不錯的選擇。
*************************
((DataRowView)Container.DataItem)["某某某"]   的效率要比   <%#   DataBinder.Eval(   Container   ,   “DataItem.Name”)   %>   高很多。  
   
  而   <%#   Eval(   “Name”   )%>   比   <%#   DataBinder.Eval(   Container   ,   “DataItem.Name”)   %>   還要多一步(多一層函數)。效率可想而知了。  
   
  當然也可能   2.0   會做什麼優化也說不定呢。
*********************
see   http://localhost/QuickStartv20/aspnet/doc/data/templates.aspx#twowaybind  
  雙向數據綁定  
  與   DetailsView   控件一樣,FormView   通過其關聯的數據源控件支持自動   Update、Insert   和   Delete   操作。若要定義編輯或插入操作的輸入   UI,可在定義   ItemTemplate   的同時定義   EditItemTemplate   或   InsertItemTemplate。在本模板中,您將對輸入控件(如   TextBox、CheckBox   或   DropDownList)進行數據綁定,以綁定到數據源的字段。但是,這些模板中的數據綁定使用“雙向”數據綁定語法,從而允許   FormView   從模板中提取輸入控件的值,以便傳遞到數據源。這些數據綁定使用新的   Bind(fieldname)   語法而不是   Eval。    
   
  重要事項:   使用   Bind   語法進行數據綁定的控件必須設置有   ID   屬性。    
   
  <asp:FormView   DataSourceID="ObjectDataSource1"   DataKeyNames="PhotoID"   runat="server">  
      <EditItemTemplate>  
          <asp:TextBox   ID="CaptionTextBox"   Text='<%#   Bind("Caption")   %>'   runat="server"/>  
          <asp:Button   Text="Update"   CommandName="Update"   runat="server"/>  
          <asp:Button   Text="Cancel"   CommandName="Cancel"   runat="server"/>  
      </EditItemTemplate>  
      <ItemTemplate>  
          <asp:Label   Text='<%#   Eval("Caption")   %>'   runat="server"   />  
          <asp:Button   Text="Edit"   CommandName="Edit"   runat="server"/>  
      </ItemTemplate>  
  </asp:FormView>  
  在對   GridView   或   DetailsView   執行更新或插入操作時,如果該控件的列或字段定義了   BoundField,GridView   或   DetailsView   負責創建   Edit   或   Insert   模式中的輸入   UI,以便它能自動提取這些輸入值以傳遞迴數據源。由於模板包含任意的用戶定義的   UI   控件,因此,需要使用雙向數據綁定語法,這樣   FormView   等模板化控件才能知道應從模板中提取哪些控件值以用於更新、插入或刪除操作。在   EditItemTemplate   中仍然可以使用   Eval   語法進行不傳遞迴數據源的數據綁定。另請注意,FormView   與   DetailsView   和   GridView   一樣,支持使用   DataKeyNames   屬性保留主鍵字段(即使這些字段並未呈現)的原始值以傳遞迴更新/插入操作。    
   
  FormView   支持使用   DefaultMode   屬性指定要顯示的默認模板,但在默認情況下,FormView   以   ReadOnly   模式啓動並呈現   ItemTemplate。若要啓用用於從   ReadOnly   模式轉換爲   Edit   或   Insert   模式的   UI,可以向模板添加一個   Button   控件,並將其   CommandName   屬性設置爲   Edit   或   New。可以在   EditItemTemplate   內添加   CommandName   設置爲   Update   或   Cancel   的按鈕,以用於提交或中止更新操作。類似地,也可以添加   CommandName   設置爲   Insert   或   Cancel   的按鈕,以用於提交或中止插入操作。    
   
  下面的示例演示一個定義了   ItemTemplate   和   EditItemTemplate   的   FormView。ItemTemplate   包含使用   Eval(單向)綁定的控件,而   EditItemTemplate   包含一個使用   Bind   語句雙向綁定的   TextBox   控件。主鍵字段   (PhotoID)   是使用   DataKeyNames   屬性在視圖狀態中進行往返的。FormView   包含用於在其模板之間進行切換的命令按鈕。    
   
   
  C#   Two-Way   Databinding   in   a   FormView   Edit   Template  
       
   
  通過使用添加到   Columns   或   Fields   集合的   TemplateField,GridView   和   DetailsView   還支持模板化   UI。TemplateField   支持使用   ItemTemplate、EditItemTemplate   和   InsertItemTemplate(僅   DetailsView)指定這些控件的不同呈現模式中的字段   UI。與上面的   FormView   示例一樣,EditItemTemplate   或   InsertItemTemplate   中的雙向綁定允許   GridView   或   DetailsView   從這些模板中的控件提取值。TemplateField   的常見用途是向   EditItemTemplate   添加驗證程序控件,用於   GridView   或   DetailsView   操作的聲明性驗證。下面的示例演示這種方法的一個示例。有關   ASP.NET   中可用的驗證控件的更多信息,請參考本教程的“驗證窗體輸入控件”部分。    
   
   
  C#   Validation   in   a   GridView   Edit   Template  
       
   
  TemplateField   的另一個用途是自定義輸入控件,這種控件用於輸入   GridView   或   DetailsView   列/字段值。例如,可以將   DropDownList   控件放在   TemplateField   的   EditItemTemplate   中,以允許從預定義的值列表進行選擇。下面的示例演示這種方法。注意,本例中的   DropDownList   與它自己的數據源控件進行了數據綁定,以便動態地獲取該列表的值。    
   
   
  C#   DropDownList   in   a   GridView   Edit   Template   
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章