深入ASP.NET数据绑定(中)——数据双向绑定机理
??? 轉載自 阿不 http://hjf1223.cnblogs.com/
在上一篇《深入ASP.NET數據綁定(上)》中,我們分析了在.NET中的數據綁定語法的一些內部機理。簡單說來就是ASP.NET在運行時為我們完成了頁面的動態編譯,并解析頁面的各種服務器端代碼,包括數據綁定語法。而數據綁定的語法雖是一些<%# %>代碼塊,在生成的代碼中,仍然使用了服務器端控件以及在DataBinding事件調用DataBinder.Eval方法來完成數據的綁定工作。所有的數據綁定模板控件都使用了這樣的機制來進行數據的單向綁定,在.NET 2.0中新增了雙向的數據綁定方式,主要用在GridView,DetailsView,FormView等數據容器控件中,結合DataSourceControl就可以非常輕松的完成數據的更新和提交工作,而不需要我們手工去遍歷輸入控件的值。那在這樣的雙向數據綁定中,ASP.NET又是做了哪些工作,來為我們透明輸入控件與字段的取值與對應關系,讓我們可以在DataSouceControl中方便得到數據項修改前的值和修改后的值?下面就讓我們一起來從一段頁面代碼開始吧:
1: <asp:DetailsDataSouce ID="DetailsDataSouce1" runat="server"> 2: </asp:DetailsDataSouce> 3: <asp:DetailsView ID="detailsView" runat="server" DefaultMode="Edit" DataSourceID="DetailsDataSouce1"> 4: <Fields> 5: <asp:TemplateField> 6: <HeaderTemplate> 7: 電流:</HeaderTemplate> 8: <EditItemTemplate> 9: <asp:TextBox ID="textBox1" runat="server" Text='<%# Bind("[電流{a}]") %>'></asp:TextBox> 10: </EditItemTemplate> 11: </asp:TemplateField> 12: </Fields> 13: </asp:DetailsView>在一個頁面中,定義了如上的一個DetailsView控件,為這個控件指定了ID為DetailsDataSource1的DataSouceControl控件,這個控件是我們自己定義的一個DataSourceControl,它返回的數據字段包括:"ID","電流{a}","電壓(v)","備注'","名稱]"。我并沒有設置DetailsView的AutoGenerateRows屬性的值,默認情況下,它是為我們自動的生成這些字段的對應的數據顯示和輸入控件。除此之外,我們還另外添加了一個數據模板字段,在這個模板中指定了編輯模板。在編輯模板中我使用了<%# Bind("")%>這樣的語法,將textBox1與"[電流{a}]"字段雙向綁定起來。
為什么這里的字段都有一些特殊呢?因為我原先的意圖是除了分析綁定語法以外,還要測試哪些特殊字符無法使用數據綁定語法來綁定數據的。這個在下篇文章中會具體介紹。
Bind與Eval不一樣,這樣的Bind并不Page或TemplateControl的一個方法,事實上我們應該把它當成一個關鍵字來看待,因為在ASP.NET的雙向數據綁定當中,并沒有這樣的一個函數存在,它的存在是只是告訴ASP.NET動態編譯頁面類時,將這個語法編譯成一定的代碼格式,并生成一些函數代理來達到雙向數據交流的目的。
那么這一段代碼,動態編譯生成的服務器代碼又是如何的呢?讓我們反編譯動態程序集,里面會找到用于創建DetailsView的__BuildControldetailsView的私有方法,在這里會調用到一些其它內部方法,我們不要讓這些方法來干擾我們的視線,直接找到創建如上模板字段的方法:
1: [DebuggerNonUserCode] 2: private TemplateField __BuildControl__control5() 3: { 4: TemplateField field = new TemplateField(); 5: field.HeaderTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control6)); 6: field.EditItemTemplate = new CompiledBindableTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control7), new ExtractTemplateValuesMethod(this.__ExtractValues__control7)); 7: return field; 8: }這里首先把this.__BuildControl__control6作為一個代理函數,用于創建頭部模板的內容,也就是如上的“電流:”字段標題。然后才是創建EditItemTemplate,這個模板又被一些的中介模板所代替,我們只需要來關心this.__BuildControl__control7和__ExtractValues__control7即可。__BuildControl__control7是為了編輯數據字段時,將數據字段的值顯示在輸入控件中(輸入控件的初始化,即字段值綁定到輸入控件中);而__ExtractValues__control7則是在提交數據時,要找出這個模板內所有的雙向綁定字段,將這些字段的值以綁定字段名為Key,以輸入控件的值為Value添加了IOrderedDictionary字典中。DetailsView等數據綁定控件調用這些委托代理來收集所有的被雙向綁定的字段的最新的值。下面分別是兩段函數的代碼片段:
1: [DebuggerNonUserCode] 2: private TextBox __BuildControl__control8() 3: { 4: TextBox box = new TextBox(); 5: box.TemplateControl = this; 6: box.ApplyStyleSheetSkin(this); 7: box.ID = "textBox1"; 8: box.DataBinding += new EventHandler(this.__DataBinding__control8); 9: return box; 10: } 11: public void __DataBinding__control8(object sender, EventArgs e) 12: { 13: TextBox box = (TextBox) sender; 14: IDataItemContainer bindingContainer = (IDataItemContainer) box.BindingContainer; 15: if (this.Page.GetDataItem() != null) 16: { 17: box.Text = Convert.ToString(base.Eval("[電流{a}]"), CultureInfo.CurrentCulture); 18: } 19: } 1: [DebuggerNonUserCode] 2: public IOrderedDictionary __ExtractValues__control7(Control __container) 3: { 4: TextBox box = (TextBox) __container.FindControl("textBox1"); 5: OrderedDictionary dictionary = new OrderedDictionary(); 6: if (box != null) 7: { 8: dictionary["[電流{a}]"] = box.Text; 9: } 10: return dictionary; 11: }由上面的代碼片段可以了解到,ASP.NET動態編譯器是將Bind語法拆分為兩部分:綁定輸出和讀取輸入控件值。綁定輸出部分與前篇介紹的機制是完全一樣的,并且也是調用DataBinder.Eval方法來綁定數據;而讀取輸入控件值則是會根據頁面上控件的類型,以及綁定的控件屬性名稱,生成一段強類型的控件屬性讀取代碼,并將控件的值保存到dictionay中返回出去。而它全然不知,容器控件是如何將這些值合并起來傳給對應的DataSouceControl控件的。
關于數據容器控件而何與DataSouceControl協同工作,并不是我們這里要分析的重點。但是我們可以簡單的描述一下工作流程,以DetailsView的數據更新為例:大家通過反編譯DetailsView的源碼,會找到名稱為HandleUpdate的私有方法,在這個方法里面會去處理數據項更新前的值(至于在Web環境中如何保存更新前的值,就需要靠ViewState的強大功能了),和更新后的值(通過ExtractRowValues函數調用類似上面生成的__ExtractValues__control7代理函數來收集所有雙向綁定字段的值存到NewValues里面),并將他們分別保存在兩個不同的IOrderedDictionary對象(OldValues,NewValues)中。然后將調用對應的DataSouceView的Update方法,傳入原字段值和新字段值和一些必須的參數,即可由我們通過重寫DataSourceView的方法來得到所有需要更新字段的原始值和新值,并可以對比比較哪些字段值是否發生了變化。NBearDataSource控件就是利用了這樣的機制來直接重DataSourceControl和DataSourceView來達到數據的全自動修改和添加方案的。
這里還有一點不得不說,在GridView,DetailsView,并不一定需要使用<%# Bind("")%>語法來實現數據的雙向綁定,他們的字段雙向綁定可以通過BoundField及它的子控件代替模板控件的綁定語法,一樣可以達到雙向綁定的目的,簡單但沒有模板來得靈活。而在存取不同版本的字段值也是類似的機制。
由于這部分涉及到的都是動態和內部代碼,如果沒有親自去閱讀這些代碼,估計還是很難理解。最后我們再來簡單總結一下:ASP.NET在模板中雙向綁定字段,是通過<%# Bind() %>這樣的語法,但是Bind我們更應該把它理解為是一個關鍵字,而不是一個函數。因為在ASP.NET的控件中,并沒有存在這個函數。ASP.NET運行時在編譯頁面代碼時,會把Bind關鍵字的代碼當成兩部分來編譯:一部分是單向綁定代碼;另一部分而是讀取對應輸入控件的綁定屬性,以綁定字段名為Key,添加到IOrderedDictionary中收集返回給數據容器控件(GridView,DetailsView,FormView)等,讓它們處理。
總體來說,ASP.NET 2.0的雙向綁定機制給我們在提交數據時帶來了極大的方便,盡管有些人很排斥DataSourceControl的模式,但是我們不可否認合理應用會大大提高我們的開發效率。希望通過這兩篇的介紹,我們能對ASP.NET數據綁定機制有更多的認識。在下一篇的文章中,我們將會介紹一些關于數據綁定方式,性能,以及對字段名的局限性等相關主題。
附上示例工程,本文分析面頁是Default3.aspx和App_Web_ryn6wtvv.dll程序集。
系列導航:
深入ASP.NET數據綁定(上)
深入ASP.NET數據綁定(下)——多樣的綁定方式
轉載于:https://www.cnblogs.com/wing626/archive/2008/08/28/1278325.html
總結
以上是生活随笔為你收集整理的深入ASP.NET数据绑定(中)——数据双向绑定机理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 北京奥运会闭幕式落下帷幕
- 下一篇: 爆牙齿的新发现:先clear:left才