資料來源控制項是Microsoft Visual Studio 2005 中引入的一種新伺服器控件,它們是資料綁定體系結構的關鍵部分,能夠透過資料綁定控件來提供聲明性程式設計模型和自動資料綁定行為。本文及此系列中的後續幾篇文章將介紹實作資料來源控制項的核心內容。
引言
簡而言之,資料來源控制項概括了一個資料儲存和可以針對所包含的資料執行的一些操作。 DataBound 控制項透過其DataSourceID 屬性與一個資料來源控制項相關聯。大多數傳統的資料儲存要么是表格格式,要么是分層的,資料來源控制項也相應地分為兩類。在此要介紹的是表格格式的資料來源控制項。
資料來源控制項本身並不能發揮多大作用;所有邏輯都封裝在DataSourceView 衍生的類別中。至少有一個DataSourceView 必須實作檢索(即SELECT)一組行的功能。它可以提供修改資料(即INSERT、UPDATE 和DELETE)的功能(可選)。資料綁定控制項可透過各種Can??? 屬性來檢查啟用功能集。資料來源控製本身只是一個或多個唯一命名視圖的容器。依據慣例,預設視圖可以按其名稱進行訪問,也可以為空。不同視圖之間是否存在關係或存在怎樣的關係可以根據每個資料來源控制項的實作情況來進行適當的定義。例如,某個資料來源控制項可能會透過不同的視圖對同一個資料提供不同的經篩選的視圖,或者可能會在輔助視圖中提供一組子行。可使用資料綁定控制項的DataMember 屬性來選擇某個特殊的視圖(如果該資料來源控制項提供了多個視圖)。請注意,Whidbey 中的所有內建資料來源控制項目前都不提供多個視圖。
最後再介紹一點內容。資料來源控制項(及其視圖)會實作兩組API。第一組API 是就四種常用的資料操作而定義的抽象介面,以常規方式從任一資料綁定控制項使用。第二組是可選的,它使用其表示的網域或資料儲存方面的術語來定義,通常被強類型化,且面向應用程式開發人員。
範例
在這些文章中,將實作一個WeatherDataSource,它將針對由weather.com(英文)提供的REST(英文)XML API 來運作,以便根據郵遞區號來檢索天氣資訊。通常會先實作派生的資料來源控制項。
public class WeatherDataSource : DataSourceControl {
public static readonly string
CurrentConditionsViewName = "CurrentConditions";
private WeatherDataSourceView _currentConditionsView;
private WeatherDataSourceView CurrentConditionsView {
get {
if (_currentConditionsView == null) {
_currentConditionsView = new WeatherDataSourceView(this, CurrentConditionsViewName);
}
return _currentConditionsView;
}
}
public string ZipCode {
get {
string s = (string)ViewState["ZipCode"];
return (s != null) ? s : String.Empty;
}
set {
if (String.Compare(value, ZipCode,
StringComparison.Ordinal) != 0) {
ViewState["ZipCode"] = value;
CurrentConditionsView.RaiseChangedEvent();
}
}
}
protected override DataSourceView GetView(string viewName) {
if (String.IsNullOrEmpty(viewName) ||
(String.Compare(viewName, CurrentConditionsViewName,
StringComparison.OrdinalIgnoreCase) == 0)) {
return CurrentConditionsView;
}
throw new ArgumentOutOfRangeException("viewName");
}
protected override ICollection GetViewNames() {
return new string[] { CurrentConditionsViewName };
}
public Weather GetWeather() {
return CurrentConditionView.GetWeather();
}
}
如您所見,基本的理念是實作GetView 以傳回一個命名視圖實例,以及實作GetViewNames 以傳回可用視圖集。
在此選擇從DataSourceControl 派生。有一點是不易察覺的,事實上資料綁定控制項要找IDataSource 介面,而DataSource 控制項透過實作GetView 和GetViewNames 來實作這個介面。之所以需要介面是為了使資料來源控制項能夠既是表格格式又是分層的(如果可能的話),在這種情況下從主要模型中派生並將另一個模型作為介面來實現)。其次,也允許在各種方案中轉換其他控件,以使資料來源的容量加倍。 另外也要注意公共ZipCode 屬性和傳回強類型化Weather 物件的GetWeather 方法。此API 適合頁面開發人員。頁面開發人員無需考慮DataSourceControl 和DataSourceView。
下一步是實作資料來源視圖本身。此特定範例僅提供了SELECT 等級功能(這只是最低要求,也是在此方案中唯一有用的功能)。
private sealed class WeatherDataSourceView : DataSourceView {
private WeatherDataSource _owner;
public WeatherDataSourceView(WeatherDataSource owner, string viewName)
: base(owner, viewName) {
_owner = owner;
}
protected override IEnumerable ExecuteSelect(
DataSourceSelectArguments arguments) {
arguments.RaiseUnsupportedCapabilitiesError(this);
Weather weatherObject = GetWeather();
return new Weather[] { weatherObject };
}
internal Weather GetWeather() {
string zipCode = _owner.ZipCode;
if (zipCode.Length == 0) {
throw new InvalidOperationException();
}
WeatherService weatherService = new WeatherService(zipCode);
return weatherService.GetWeather();
}
internal void RaiseChangedEvent() {
OnDataSourceViewChanged(EventArgs.Empty);
}
}
預設情況下,DataSourceView 類別從諸如CanUpdate 等的屬性傳回false,而從Update 和相關方法拋出NotSupportedException。在此,在WeatherDataSourceView 中唯一需要做的就是替代抽象的ExecuteSelect 方法,傳回包含「選取」天氣資料的IEnumerable。在實作過程中,使用了幫助程式WeatherService 類別,該類別僅使用WebRequest 物件來查詢weather.com(英文),方法是使用所選的郵遞區號(這沒什麼特別的)。
您可能注意到了,ExecuteSelect 被標記為受保護。資料綁定控制項實際呼叫的是在回撥中傳遞的公共(和密封)Select 方法。 Select 的實作會呼叫ExecuteSelect,並呼叫回撥與得到的IEnumerable 實例。這種模式非常古怪。這其中有一個原因,此系列隨後的文章將會加以說明。請稍候...
以下是該用法的範例:
Zip Code: <asp:TextBox runat="server" id="zipCodeTextBox" />
<asp:Button runat="server" onclick="OnLookupButtonClick" Text="查找" />
<hr />
<asp:FormView runat="server" DataSourceID="weatherDS">
<ItemTemplate>
<asp:Label runat="server"
Text='<%# Eval("Temperature", "目前溫度是{0}。") %>' />
</ItemTemplate>
</asp:FormView>
<nk:WeatherDataSource runat="server" id="weatherDS" ZipCode="98052" />
<script runat="server">
private void OnLookupButtonClick(object sender, EventArgs e) {
weatherDS.ZipCode = zipCodeTextBox.Text.Trim();
}
</script>
此程式碼設定了郵遞區號來回應使用者輸入,這會使資料來源發出變更通知,從而使綁定的FormView 控制項執行資料綁定並變更顯示。
現在,資料存取代碼就被封裝在資料來源控制項中。此外,透過此模型,weather.com(英文)能夠發布一個元件,該元件還可以封裝特定於其服務的詳細資訊。但願它會好用。此外,抽象的資料來源介面允許FormView 僅針對天氣資料進行工作。
在下一篇文章中,將增強資料來源控制項的功能,使其能夠自動處理用來查詢資料的篩選值(即郵遞區號)的變更。