在上一篇《深入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: }