【阿不】深入ASP.NET資料繫結(上)
在ASP.NET我們在使用Repeater,DetailsView,FormView,GridView等資料繫結模板時,都會使用或這樣的語法來單向或雙向繫結資料。但是我們卻很少去了解,在這些語法的背後,ASP.NET究竟都做了哪些事情來方便我們使用這樣的語法來繫結資料。究竟解析這樣的語法是在編譯時,還是執行時?如果沒有深入去了解,我們肯定不得而知。這個簡短的系列文章就是帶我們大家一起去深入探究一下ASP.NET繫結語法的內部機理,以讓我們更加全面的認識和運用它。
事件的起因是,我希望動態的為Repeater控制元件新增行項模板,我可以通過實現ITempate介面的方式來動態新增行模板。並希望它通過普通的頁面繫結語法來完成資料欄位的繫結功能,如下就是一個簡單的例子:
1: ///
2: /// Summary description for DynamicTemplate
3: ///
4: public class DynamicTemplate : ITemplate
5: {
6: public DynamicTemplate()
7: {
8: //
9: // TODO: Add constructor logic here
10: //
11: }
12: #region ITemplate Members
13:
14: public void InstantiateIn(Control container)
15: {
16: TextBox textBox = new TextBox();
17: textBox.Text = @""ID"") %>";
18: container.Controls.Add(textBox);
19: }
20: #endregion
21: }
在這個例子中,我在模板中新增了一個TextBox控制元件,並指定它的繫結欄位是“ID”。但是這做法,能否實現我們實現我們需要的功能呢?答案是否定,每一行的TextBox的值都是"",而不會像我們希望的那樣去繫結ID欄位。從結果來分析原因,我們可以非常容易得出,這段繫結語法並沒有得到ASP.NET執行時的承認,那麼頁面中使用相同的語法為什麼可以呢?故事就是從這裡開始的。
我們首先要去了解下,在頁面中使用這樣的語法ASP.NET都為我們做了哪些事情呢?要了解這個,我們要找到.aspx檔案在首次執行時動態編譯的程式集。
我們都知道,在ASP.NET執行時,也會把.aspx檔案編譯成一個動態類,這個類是繼承於.aspx的Page指令中Inherits屬性指定的類並且同時也直接實現了IHttpHandler介面。這個動態類會負責建立頁面中使用的各種伺服器端控制元件的例項,並且ASP.NET執行時會負責解析的編譯.aspx中存在的伺服器端程式碼(包括繫結語法)並將這些程式碼編譯到這個頁面類。WebSite工程和Web Application在頁面檔案上有些不同,WebSite工程的每個頁面最多可以有兩個檔案:.aspx和.aspx.cs檔案;而在Web Application還可以包括.aspx.designer.cs檔案,這個檔案所起的作用也非常有限,也就是為了能在頁面程式碼中使用伺服器端、控制元件例項而定義的一個例項變數,僅此而已。所以在設計時WebSite具備更多的動態行為,而在執行時WebSite工程和Web Application並沒有太大區別。
如何得到頁面的動態類呢?要首先得到這個頁所在的動態程式集,在Vista以前的作業系統上,一般是在:%SystemRoot%\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files 資料夾下,而在Vista中,而會在:%USERPROFILE%\AppData\Local\Temp\Temporary ASP.NET Files下。那麼如何快速得到程式集的路徑和名稱?你可以讓你的Web工程動態編譯出錯(比如重複的類名),就可以快速定位到當前動態程式集的目錄了。
動態類中會有很多的內容,我們不作更多的分析,我們把目光集中繫結程式碼上。假設現在頁面上有這麼一段Repeater繫結程式碼:
1:"server" ID="repeater">
2:
3:
6: ID 7: | 9: 電流{a} 10: | 電壓(V) | 13: 備註' 14: | 16: 名稱] 17: |
23: 24: | 26: 27: | 30: ")%> 31: | 33: 名稱]")%> 34: |
39:
40:
那麼在動態類中,相應的會有這樣的一段函式,是用來建立ID為repeater的控制元件例項:
1: [DebuggerNonUserCode]
2: private Repeater __BuildControlrepeater()
3: {
4: Repeater repeater = new Repeater();
5: base.repeater = repeater;
6: repeater.HeaderTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control4));
7: repeater.ItemTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control5));
8: repeater.FooterTemplate = new CompiledTemplateBuilder(new BuildTemplateMethod(this.__BuildControl__control7));
9: repeater.ID = "repeater";
10: return repeater;
11: }
12:
13:
CompiledTempateBuilder和BuildTemplateMethod只是模板例項化的一箇中介,真正用於新增模板內容的是後面的那些私有函式,如ItemTempate的模板內容例項的建立就在__BuildControl__control5函式中,這個函式原型定義是:
1: [DebuggerNonUserCode]
2: private void __BuildControl__control5(Control __ctrl)
3: {
4: DataBoundLiteralControl control = this.__BuildControl__control6();
5: IParserAccessor accessor = __ctrl;
6: accessor.AddParsedSubObject(control);
7: }
8:
在這個函式裡,呼叫了另一個私有函式this.__BuildControl__control6,這個函式返回的一個DataBoundLiteralControl物件,並將物件輸出新增到__ctrl引數。事實上,只要我們去閱讀CompiledTempateBuilder就發現在,這裡的__ctrol物件就是我們在例項化模板時傳入的物件,也就是ITemplate中的InstantiateIn方法的那個container引數物件。
為什麼使用的是AddParsedSubObject方法,使用這個方法新增子控制元件相當於告訴父控制元件,這是一個已經解析好的子控制元件物件,不需再去將控制元件解析成HTML程式碼,而在輸出時直接輸出Text屬性的值即可。從這裡我們還可以得知DataBoundLiteralControl的物件,事實上就是承擔了字串拼接的職責,這一點我們可以在後面的分析中得以驗證。
__BuildControl__control6私有函式的定義如下:
1: [DebuggerNonUserCode]
2: private DataBoundLiteralControl __BuildControl__control6()
3: {
4: DataBoundLiteralControl control = new DataBoundLiteralControl(5, 4);
5: control.TemplateControl = this;
6: control.SetStaticString(0, "\r\n\r\n \r\n ");\r\n "); \r\n7: control.SetStaticString(1, "\r\n\r\n "); \r\n \r\n8: control.SetStaticString(2, "\r\n\r\n "); \r\n9: control.SetStaticString(3, "\r\n\r\n "); \r\n10: control.SetStaticString(4, "\r\n
11: control.DataBinding += new EventHandler(this.__DataBind__control6);
12: return control;
13: }
在這個函式裡面,建立了一個DataBoundLiteralControl物件,並將頁面上定義的模板的靜態HTML程式碼新增到該的靜態字串陣列裡,並且設定了它的繫結事件代理函式__DataBind__control6,該函式的定義:
1: public void __DataBind__control6(object sender, EventArgs e)
2: {
3: DataBoundLiteralControl control = (DataBoundLiteralControl) sender;
4: RepeaterItem bindingContainer = (RepeaterItem) control.BindingContainer;
5: control.SetDataBoundString(0, Convert.ToString(base.Eval("ID"), CultureInfo.CurrentCulture));
6: control.SetDataBoundString(1, Convert.ToString(base.Eval("電流{a}"), CultureInfo.CurrentCulture));
7: control.SetDataBoundString(2, Convert.ToString(base.Eval("備註'"), CultureInfo.CurrentCulture));
8: control.SetDataBoundString(3, Convert.ToString(base.Eval("名稱]"), CultureInfo.CurrentCulture));
9: }
在這個函式中,我們看到了真正的資料繫結程式碼了,它呼叫了TemplateControl的Eval方法來將當前資料項的相應欄位的值取出,並按一定的格式轉化後新增到DataBoundLitreralControl物件中,並在DataBoundLiteralControl將StaticString和DataBoundString字串陣列按一定的順序拼接起來,作為Text屬性的輸出值。而容器控制元件則直接向客戶端輸這段HTML。
下面,我們還有必要來分析下TemplateControl中的Eval方法,這個方法有兩種過載,簡單起見,我們來分析較為簡單的過載:
1: protected internal object Eval(string expression)
2: {
3: this.CheckPageExists();
4: return DataBinder.Eval(this.Page.GetDataItem(), expression);
5: }
這個方法,使用了DataBinder.Eval靜態方
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-402158/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 【阿不】深入ASP.NET資料繫結(中)—資料雙向繫結機理ASP.NET
- 【阿不】深入ASP.NET資料繫結(下)—多樣的繫結方式ASP.NET
- 資料繫結
- 簡單資料繫結和複雜資料繫結
- JavaScript 進階之深入理解資料雙向繫結JavaScript
- 資料繫結原理
- ASP.NET MVC模型繫結——繫結部分欄位ASP.NETMVC模型
- FlatList 資料繫結 及上拉載入實現
- 第二講、Vue3.x繫結資料、繫結html、繫結屬性、迴圈資料VueHTML
- Vue的資料繫結Vue
- 資料繫結之謎
- 【Angular-資料繫結】Angular
- 2、理解資料繫結
- Angular | 理解資料繫結Angular
- 深入理解 Object.defineProperty 及實現資料雙向繫結Object
- 深入理解Proxy 及 使用Proxy實現vue資料雙向繫結Vue
- 網上繫結 for RedhatRedhat
- SpringMVC【引數繫結、資料回顯、檔案上傳】SpringMVC
- 如果將json格式資料繫結與表單元素上JSON
- Vue資料繫結簡析Vue
- vue資料繫結原始碼Vue原始碼
- Binding(一):資料繫結
- JS雙向資料繫結JS
- SpringMVC資料繫結demoSpringMVC
- Flex 資料繫結備忘Flex
- javascript實現資料的雙向繫結(手動繫結)JavaScript
- asp.net Oracle資料庫左側目錄樹及右側資料繫結及分頁ASP.NETOracle資料庫
- 【ASP.NET Core】繫結到 CancellationToken 物件ASP.NET物件
- 深入理解 C++ 的動態繫結和靜態繫結C++
- angular1資料繫結例子Angular
- Vue資料雙向繫結原理Vue
- vue雙向資料繫結原理Vue
- Winform控制元件繫結資料ORM控制元件
- Study Blazor .NET(四)資料繫結Blazor
- 原生js雙向資料繫結JS
- XAML資料繫結(Data Binding)
- Vue.js資料繫結原理Vue.js
- [JS] 資料雙向繫結原理JS