四、例2—數據庫綁定 現在,我們來討論更為復雜的數據庫綁定的例子。根據我們前面的討論,我們找到了使用DataSource的典型場所;在前面的例1中,我們使用了一種內存數據來模擬有狀態的web服務。但是,在實際開發中,一般不這樣使用。在本節中,我們要創建一個非常貼近于實際開發環境應用的例子。
1.創建工程
啟動Visual Studio 2005并選用模板“ASP.NET AJAX CTP-Enabled Web Site”創建一個新的網站并命名為DatabaseBinding,最后選定Visual C#為內置語言。然后,稍微修改頁面Default.aspx,最后的結果如下圖4所示。
2.后臺代碼分析
下面是頁面Default.aspx中HTML元素的定義部分。
列表6
<!--------------------------------------------------->
<div id="detailsView"></div>
<!--------------------------------------------------->
<input type="button" id="previousButton" value="Previous"
title="Go to previous row" style="width: 67px; height: 30px;" />
<span id="rowIndexLabel"></span>
<input id="nextButton" type="button" value="Next" title="Go to next row"
style="width: 67px; height: 30px;" />
<input type="button" id="addButton" value="Add" title="Create a new row"
style="width: 67px; height: 30px;" />
<input type="button" id="delButton" value="Delete"
title="Delete the current row" style="width: 67px; height: 30px;" />
<input type="button" id="saveButton" value="Save"
title="Save all pending changes" style="width: 67px; height: 30px;" />
<input type="button" id="refreshButton" value="Refresh"
title="Discard pending changes and get the latest data from the server"
style="width: 73px; height: 30px" />
<!--------------------------------------------------->
<div style="visibility:hidden;display:none" >
<div id="detailsTemplate" class="ListWindow">
Name: <input id="nameField" size="30" /><br />
Address:<br />
<textarea id="addressField" style="width: 428px;
height: 130px" rows="4" cols="4"></textarea><br />
</div>
<div id="emptyTemplate">
Loading Data...
</div>
</div> |
根據圖4中的布局和上面的代碼,我們在此首先定義了兩個導航按鈕—previousButton和nextButton—它們都用于顯示于客戶端(而不是服務器端)的控件ItemView相應的數據源的數據記錄間的導航。然后,我們定義了兩個按鈕(addButton,delButton)以實現對數據庫中記錄的修改操作。最后兩個按鈕—saveButton和refreshButton直接相應于MS AJAX客戶端控件DataSource的save和load兩個方法。之后,我們使用了一組HTML DIV元素來描述控件ItemView。在此,建議你把這里的對應關系與例一1中的控件ListView與HTML元素的對應關系加以比較。
3.創建一個連接到數據庫的Web服務
(1)創建一個示例數據庫—DataBind.mdf
右擊工程并選定“添加新項”,然后選擇模板“SQL數據庫”,你可以容易地創建一個空的數據庫—在此,我們命名它為DataBind.mdf。然后,我們把唯一的一個表(Employees)添加到其中。這個表中包含三個字段:Id(int,primary key),Name(nvarchar(50),not empty)和Address (nvarchar(50),not empty)。同時,我們還創建了四個簡單的存儲過程:DeleteRecord,GetAllRecords,InsertRecord,UpdateRecord,它們相應于典型的數據庫CRUD操作。因為我們的重點不在此,所以不再詳細加以討論。
(2)創建一個類—Employee
注意,這個類非常類似于第一個例子中的類Employees—充當數據庫表格的OOP包裝;具體地說,這是通過把它的修飾有屬性DataObjectField的成員變量映射到定義于表格Employees中的字段實現的。
(3)兩個幫助者類—SqlHelper(來自于MS AJAX示例中)和SqlTaskProvider
為了問題的簡化和通用起見,我們創建了兩個幫助者類。一個是SqlHelper(來自于隨同MS AJAX發行的示例程序TaskList);另一個是SqlTaskProvider。由于這些內容有些遠離了本文的主題,所以,在此也不多解釋,有興趣的讀者可詳細研究本文所附源碼。
現在,讓我們來創建一個DataService(派生自Web Service)并使之與數據庫相連接。
2.創建連接到數據庫的DataService
下面,我們先列出這個DataService相關的MyDataService.asmx的關鍵代碼:
列表7
//……(省略)
using System.ComponentModel;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Data;
using System.Web.Script.Services;
using Microsoft.Web.Preview.Services;
using Demos.Employee;//defines class SqlTaskProvider
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class MyDataService : DataService
{
[WebMethod]
[DataObjectMethod(DataObjectMethodType.Delete)]
public void DeleteRecord(Employee emp)
{
if (emp.Name == null)
{
throw new AccessViolationException();
}
new SqlTaskProvider().DeleteRecord(emp);
}
[WebMethod]
[DataObjectMethod(DataObjectMethodType.Select)]
public List<Employee> GetAllRecords()
{
return new SqlTaskProvider().GetAllRecords();
}
[WebMethod]
[DataObjectMethod(DataObjectMethodType.Insert)]
public void InsertRecord(Employee emp)
{
if (emp.Name == null)
{
throw new AccessViolationException();
}
new SqlTaskProvider().InsertRecord(emp);
}
[WebMethod]
[DataObjectMethod(DataObjectMethodType.Update)]
public void UpdateRecord(Employee emp)
{
if (emp.Name == null)
{
throw new AccessViolationException();
}
new SqlTaskProvider().UpdateRecord(emp);
}
} |
略微加以分析,你應該得如圖5所示的調用關系圖:
接下來,讓我們分析數據綁定是如何在客戶端實現的。注意,這里我們仍然使用xml-script聲明性方式。
4.客戶端聲明性編程
在此,非常類似于前一個例子,我們首先建立HTML元素與控件ItemView的模板間的映射關系:
列表8
<script type="text/xml-script">
<page xmlns:script="http://schemas.microsoft.com/xml-script/2005">
<components>
<dataSource id="EmployeeDataSource" serviceURL="MyDataService.asmx" >
</dataSource> <itemView id="detailsView">
<bindings>
<binding dataContext="EmployeeDataSource"
dataPath="data" property="data" />
<binding dataContext="EmployeeDataSource"
dataPath="isReady"?? property="element" propertyKey="enabled"/>
</bindings>
<itemTemplate>
<template layoutElement="detailsTemplate">
<textBox id="nameField">
<bindings>
<binding dataPath="Name"
property="text" direction="InOut"/>
</bindings>
</textBox>
<textBox id="addressField">
<bindings>
<binding dataPath="Address"
property="text" direction="InOut"/>
</bindings>
</textBox>
</template>
</itemTemplate>
<emptyTemplate>
<template layoutElement="emptyTemplate" />
</emptyTemplate>
</itemView> |
在此,有幾處需要注意。首先,控件ItemView典型地用于顯示一條記錄—基于MS AJAX客戶端數據綁定方案,而控件ListView卻用于顯示滿足一定范圍的一批記錄。其次,控件ItemView使用了兩個綁定:第一個綁定將把從DataSource返回的數據綁定到控件ItemView的data屬性上,以確保ItemView控件能夠從數據源取得它所要求的完整的數據;第二個綁定把ItemView控件的enabled屬性綁定到DataSource的IsReady屬性上。這意味著,當數據源還沒有準備好時(例如數據源正在從服務器端讀寫數據),控件ItemView將被禁用。第三,我們使用了雙向綁定技術,這意味著不僅源控件屬性(dataContext屬性指向的那個)的改變將更新目標控件相應的屬性,而且反過來也如此。最后,我們還要注意,DataSource的改變將使數據變‘臟’—DataSource控件的isDirty屬性將被置為true。
接下來,讓我們看一下頁面中使用的兩個導航按鈕的定義。
列表9
<button id="previousButton">
<click>
<invokeMethodAction target="detailsView" method="movePrevious" />
</click>
<bindings>
<binding dataContext="detailsView" dataPath="canMovePrevious"?
property="element" propertyKey="disabled" transform="Invert" />
</bindings>
</button>
<label id="rowIndexLabel">
<bindings>
<binding dataContext="detailsView" dataPath="dataIndex"
property="text" transform="Add" />
</bindings>
</label>
<button id="nextButton">
<click>
<invokeMethodAction target="detailsView" method="moveNext" />
</click>
<bindings>
<binding dataContext="detailsView" dataPath="canMoveNext"?
property="element" propertyKey="disabled" transform="Invert" />
</bindings>
</button> |
在此,控件ItemView提供的一些方法和屬性用于實現加載到其中的相鄰記錄之間的導航。如果用戶正在瀏覽第一條記錄,那么屬性canMovePrevious被設置為false;否則為true。此外,我們還為按鈕previousButton的click事件指定了一個相應的行為。至于按鈕nextButton,情況與之一致。另外,我們通過dataIndex屬性來讀取當前記錄的索引值并把它綁定到label控件。
現在,讓我們來討論最有趣也是最重要的與數據庫相關的CRUD操作部分。
列表10
<button id="addButton">
<click>
<invokeMethodAction target="detailsView" method="addItem" />
</click>
<bindings>
<binding dataContext="EmployeeDataSource" dataPath="isReady"?
property="element" propertyKey="disabled" transform="Invert" />
</bindings>
</button> <button id="delButton">
<click>
<invokeMethodAction target="detailsView" method="deleteCurrentItem" />
</click>
<bindings>
<binding dataContext="EmployeeDataSource" dataPath="isReady"?
property="element" propertyKey="disabled" transform="Invert" />
</bindings>?
</button> <button id="saveButton">
<click>
<invokeMethodAction target="EmployeeDataSource" method="save" />
</click>
<bindings>
<binding dataContext="EmployeeDataSource" dataPath="isDirtyAndReady"?
property="element" propertyKey="disabled" transform="Invert" />
</bindings>
</button> <button id="refreshButton">
<click>
<invokeMethodAction target="EmployeeDataSource" method="load" />
</click>
<bindings>
<binding dataContext="EmployeeDataSource" dataPath="isReady"?
property="element" propertyKey="disabled" transform="Invert" />
</bindings>?
</button> |
在此,當我們需要向數據集中添加新記錄時,調用控件ItemView的addItem方法—此時數據源必須準備好。對于按鈕delButton,情況也非常類似。當數據源準備好后,調用控件ItemView的方法deleteCurrentItem;否則按鈕delButton被置為disabled。
對于按鈕saveButton,情況則比較復雜。只有當數據源變‘臟’并且數據源已經準備好后,我們才能夠保存數據。讀者應該還記得在前面定義的那幾個TextBox控件(它們位于ItemView控件的ItemTemplate模板內,并且都是進行雙向的數據綁定)。所以,當用戶更改任何一個TextBox控件中的內容時,ItemView控件的數據集將被自動更新,而且其數據源中的數據集也是如此。最后,數據源變‘臟’;同時,數據源也準備好,于是屬性isDirtyAndReady被置為true—此時,按鈕saveButton才會激活可用;否則不可用。
當你點擊按鈕refreshButton時,將再次發生一次SELECT查詢,這又進一步觸發所有綁定并把最新數據加載到當前頁面中的控件內。請注意,這里的刷新操作是以AJAX方式(異步)實現的,因此,僅有控件ItemView被更新而不會產生整個頁面的閃爍問題。
4.運行程序
如果沒有什么問題的話,按下F5鍵,你將會看到如下圖6所示的運行時刻快照。
乍看這個屏幕,你會感覺它非常類似一個傳統的桌面數據庫應用程序的界面,但實際上其中顯示的數據卻是來自于一個遠方的服務數據庫!在此,我們再次領略了MS AJAX框架的威力。
五、總結
在本系列的這兩篇文章中,我們深入剖析了微軟ASP.NET Ajax中的數據綁定構架。因為本人也是這個框架的新手,而且這個框架也一直處于發展當中(特別是Futures CTP部分),所以在其中涉及的許多概念和例子里面很可能存在一定的錯誤,真誠希望讀者朋友能夠幫助批評指正。
轉載于:https://www.cnblogs.com/xujiaci/archive/2007/09/13/891431.html
總結
以上是生活随笔為你收集整理的深入剖析微软ASP.NET Ajax中的数据绑定构架下篇之二的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。