ASP.NET2.0中使用數據源控件之參數
數據源控件需要使用參數值來指定需要選擇哪些數據,或者指定如何修改數據以及修改什么數據。通常情況下,頁面包含一些 UI,以定義那些必須在選擇操作中使用的參數,而數據綁定控件提供了參數值來進行插入、更新和刪除操作。但是,在任意一種情況下,都可能同時出現兩種現象。在第 1 部分中,數據源控件揭示了 ZipCode 屬性,該屬性可進行聲明性設置,或者以編碼來設置以響應用戶操作。參數被設計為以聲明性(且可擴展)的方式來完成此方案。
引言
Parameter 基類代表一個通用參數。Microsoft Visual Studio 2005 提供了諸如 QueryStringParameter 之類的參數,以便將數據從查詢字符串參數請求到數據源中。另一個非常有用的參數是 ControlParameter,該參數允許從任一控件屬性中請求數據。如果內置參數類型不能滿足您的要求,則您可以定義自己的參數類型。這樣您就可以使頁面與粘接代碼不相關,而是將該代碼整齊地封裝在參數實現中。
除了從不同的源中請求值,這些參數還可以跟蹤值的更改情況,并通知這些更改的所屬數據源,進而引發數據源更改通知,最終在數據綁定控件中觸發數據綁定操作。簡而言之,這就是使用 ControlParameters 時,主要的聲明性詳細方案所依據的原理。
示例
在此將向 WeatherDataSource 添加參數功能,然后進一步闡述。
Microsoft ASP.NET 提供了 ParameterCollection,您可以完全按原樣使用該集合。它同時包含更改跟蹤和狀態管理功能。您只需相應地調用該集合的 API 來合并這些功能,另外還可以在控件外將該集合揭示為屬性。在上述代碼中,需要注意的關鍵點為:
·該數據源控件揭示了一個 ParameterCollection 類型的屬性,以使開發人員能夠添加表示要使用的郵政編碼值的參數。如果已經設置了參數,則使用該參數;否則,將使用 ZipCode 屬性值。
·該控件替代了與狀態管理相關的方法,以請求 ParameterCollection 中內置的狀態管理功能。
·該控件使用頁面生命周期的新 LoadComplete 事件來更新參數值,它通過替代 OnInit 來注冊這些值。如果在初始化、回發處理或頁面編碼(當引發 LoadComplete 時,全部都會發生)期間更改了任何參數的值,則該數據源控件還會注冊 ParameterCollection 所引發的 ParametersChanged 事件。與上述情況一樣,如果設置了 ZipCode 屬性,將會引發更改通知,向數據綁定控件指明它需要再次執行數據綁定操作(隨后在 PreRender 期間將會發生此情況)。
·需要參與生命周期是數據源作為控件(即使是非可視控件)來實現的一個原因。另一個原因是為了使數據綁定控件能夠通過使用其 DataSourceID 屬性來使用 FindControl,并能夠獲得基于 INamingContainer 的分層名稱領域的益處(這樣就能夠實現嵌套數據方案,方法是在模板內放置一個數據源控件,并使其在每行中重復一次)。數據源是控件這一事實早已是爭論的焦點 - 但愿這能夠說明此問題的一些論據。
在此 DataSourceView 只需調用 GetSelectedZipCode,而不是直接使用 ZipCode 屬性。此外,還更改了數據源視圖代碼,以便在未選中 ZipCode 的情況下返回 null(而不是拋出異常),這會導致數據綁定控件顯示“空”視圖。這在通常情況下是一個慣例,但是回顧來看,這應該成為數據源控件語義的一個不可獲缺的方面。
完整的代碼就是這個樣子。以下是經過更新的用法示例,該示例現在是聲明性的。
請注意,在標記中并未指定 Text 作為在 ControlParameter 標記上查找的屬性。ControlParameter 自動計算出了在未指定屬性的情況下要使用的默認屬性。它通過檢查該類中的 ControlValueAttribute 來實現此目的。TextBox 將 Text 定義為包含其“控件值”的屬性。除了傳統輸入控件之外,此概念還適用于多個控件。例如,GridView 將其 SelectedDataKey 揭示為“控件值”。這是一個新事物,控件開發人員從此以后應該予以考慮,以便與 ControlParameter 更好地進行集成。
引言
Parameter 基類代表一個通用參數。Microsoft Visual Studio 2005 提供了諸如 QueryStringParameter 之類的參數,以便將數據從查詢字符串參數請求到數據源中。另一個非常有用的參數是 ControlParameter,該參數允許從任一控件屬性中請求數據。如果內置參數類型不能滿足您的要求,則您可以定義自己的參數類型。這樣您就可以使頁面與粘接代碼不相關,而是將該代碼整齊地封裝在參數實現中。
除了從不同的源中請求值,這些參數還可以跟蹤值的更改情況,并通知這些更改的所屬數據源,進而引發數據源更改通知,最終在數據綁定控件中觸發數據綁定操作。簡而言之,這就是使用 ControlParameters 時,主要的聲明性詳細方案所依據的原理。
示例
在此將向 WeatherDataSource 添加參數功能,然后進一步闡述。
public class WeatherDataSource : DataSourceControl { public static readonly string ZipCodeParameterName = "ZipCode"; ... private ParameterCollection _parameters; private ParameterCollection Parameters { get { if (_parameters == null) { _parameters = new ParameterCollection(); _parameters.ParametersChanged += new EventHandler(this.OnParametersChanged); if (IsTrackingViewState) { ((IStateManager)_parameters).TrackViewState(); } } return _parameters; } } ... public string GetSelectedZipCode() { if (_parameters != null) { Parameter zipCodeParameter = _parameters[ZipCodeParameterName]; if (zipCodeParameter != null) { IOrderedDictionary parameterValues = _parameters.GetValues(Context, this); return (string)parameterValues[zipCodeParameter.Name]; } } return ZipCode; } protected override void LoadViewState(object state) { object baseState = null; if (state != null) { Pair p = (Pair)state; baseState = p.First; if (p.Second != null) { ((IStateManager)Parameters).LoadViewState(p.Second); } } base.LoadViewState(baseState); } protected override void OnInit(EventArgs e) { Page.LoadComplete += new EventHandler(this.OnPageLoadComplete); } private void OnPageLoadComplete(object sender, EventArgs e) { if (_parameters != null) { _parameters.UpdateValues(Context, this); } } private void OnParametersChanged(object sender, EventArgs e) { CurrentConditionsView.RaiseChangedEvent(); } protected override object SaveViewState() { object baseState = base.SaveViewState(); object parameterState = null; if (_parameters != null) { parameterState = ((IStateManager)_parameters).SaveViewState(); } if ((baseState != null) || (parameterState != null)) { return new Pair(baseState, parameterState); } return null; } protected override void TrackViewState() { base.TrackViewState(); if (_parameters != null) { ((IStateManager)_parameters).TrackViewState(); } } } |
Microsoft ASP.NET 提供了 ParameterCollection,您可以完全按原樣使用該集合。它同時包含更改跟蹤和狀態管理功能。您只需相應地調用該集合的 API 來合并這些功能,另外還可以在控件外將該集合揭示為屬性。在上述代碼中,需要注意的關鍵點為:
·該數據源控件揭示了一個 ParameterCollection 類型的屬性,以使開發人員能夠添加表示要使用的郵政編碼值的參數。如果已經設置了參數,則使用該參數;否則,將使用 ZipCode 屬性值。
·該控件替代了與狀態管理相關的方法,以請求 ParameterCollection 中內置的狀態管理功能。
·該控件使用頁面生命周期的新 LoadComplete 事件來更新參數值,它通過替代 OnInit 來注冊這些值。如果在初始化、回發處理或頁面編碼(當引發 LoadComplete 時,全部都會發生)期間更改了任何參數的值,則該數據源控件還會注冊 ParameterCollection 所引發的 ParametersChanged 事件。與上述情況一樣,如果設置了 ZipCode 屬性,將會引發更改通知,向數據綁定控件指明它需要再次執行數據綁定操作(隨后在 PreRender 期間將會發生此情況)。
·需要參與生命周期是數據源作為控件(即使是非可視控件)來實現的一個原因。另一個原因是為了使數據綁定控件能夠通過使用其 DataSourceID 屬性來使用 FindControl,并能夠獲得基于 INamingContainer 的分層名稱領域的益處(這樣就能夠實現嵌套數據方案,方法是在模板內放置一個數據源控件,并使其在每行中重復一次)。數據源是控件這一事實早已是爭論的焦點 - 但愿這能夠說明此問題的一些論據。
在此 DataSourceView 只需調用 GetSelectedZipCode,而不是直接使用 ZipCode 屬性。此外,還更改了數據源視圖代碼,以便在未選中 ZipCode 的情況下返回 null(而不是拋出異常),這會導致數據綁定控件顯示“空”視圖。這在通常情況下是一個慣例,但是回顧來看,這應該成為數據源控件語義的一個不可獲缺的方面。
private sealed class WeatherDataSourceView : DataSourceView { ... internal Weather GetWeather() { string zipCode = _owner.GetSelectedZipCode(); if (zipCode.Length == 0) { return null; } WeatherService weatherService = new WeatherService(zipCode); return weatherService.GetWeather(); } } |
完整的代碼就是這個樣子。以下是經過更新的用法示例,該示例現在是聲明性的。
Zip Code: <asp:TextBox runat="server" id="zipCodeTextBox" /> <asp:Button runat="server" 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"> <Parameters> <asp:ControlParameter Name="ZipCode" ControlID="zipCodeTextBox" /> </Parameters> </nk:WeatherDataSource> |
請注意,在標記中并未指定 Text 作為在 ControlParameter 標記上查找的屬性。ControlParameter 自動計算出了在未指定屬性的情況下要使用的默認屬性。它通過檢查該類中的 ControlValueAttribute 來實現此目的。TextBox 將 Text 定義為包含其“控件值”的屬性。除了傳統輸入控件之外,此概念還適用于多個控件。例如,GridView 將其 SelectedDataKey 揭示為“控件值”。這是一個新事物,控件開發人員從此以后應該予以考慮,以便與 ControlParameter 更好地進行集成。