共用方式為


開發 ASP.NET 2.0 的自訂資料繫結 Web 伺服器控制項

更新:2007 年 11 月

ASP.NET 資料繫結 Web 伺服器控制項提供了使用者介面 (UI) 給表示資料錄或項目之集合的資料來源。GridView Web 伺服器控制項概觀DataList Web 伺服器控制項概觀Repeater Web 伺服器控制項概觀 伺服器控制項都是資料繫結 Web 伺服器控制項的範例。如需 ASP.NET 包含之資料繫結控制項的詳細資訊,請參閱 ASP.NET 資料繫結 Web 伺服器控制項概觀

在 ASP.NET 2.0 版中,新資料來源模型讓您可以把資料繫結控制項繫結至來源控制項,允許將一般資料作業 (例如分頁、排序和刪除) 自資料繫結控制項本身中移出。這種模型可以為網頁開發人員產生更有彈性的資料繫結控制項,並提升可重複使用性的等級。

本主題介紹的是實作自訂 ASP.NET 2.0 資料繫結伺服器控制項所需的基本步驟。如需自訂控制項之一般架構及實作 (Implementation) 的詳細資訊,請參閱開發自訂的 ASP.NET 伺服器控制項逐步解說:開發和使用自訂的伺服器控制項。如需開發 ASP.NET 1.1 相容資料繫結控制項的詳細資訊,請參閱開發 ASP.NET 1.1 的自訂資料繫結 Web 伺服器控制項逐步解說:建立 ASP.NET 1.1 的自訂資料繫結 ASP.NET Web 控制項。如需資料來源控制項的詳細資訊,請參閱資料來源控制項概觀

何時建立自訂資料繫結控制項

在建立自己的自訂資料繫結控制項之前,先檢閱 ASP.NET 已經提供的資料繫結控制項能力。現有控制項可能符合了您的需求,或者您可能決定從已有許多所需之功能的現有控制項中加以擴充,進而建立自訂控制項。如需 ASP.NET 提供之資料繫結控制項的詳細資訊,請參閱 ASP.NET 資料繫結 Web 伺服器控制項概觀

基於以下幾個原因,您可能決定建立自訂資料繫結控制項:

  • 特定需求所需的是現有資料繫結控制項中沒有的自訂 UI、自訂資料排序功能或自訂資料編輯功能。

  • 您想要建立先行編譯及可轉散發的自訂資料繫結控制項。

  • 您想要擴充 ASP.NET 已提供的資料繫結控制項功能。

  • 您想要以符合特定需求的自訂設計工具來建立資料繫結控制項。

自訂資料繫結控制項的基本功能

藉由衍生自其中一個資料繫結控制項基底類別 (Base Class),例如 DataBoundControl 類別或 CompositeDataBoundControl 類別,自訂資料繫結控制項會自動繼承許多內建功能,包括下列各項:

  • IDataSource 介面及其相關 DataSourceView 類別的資料來源支援,提供了具名資料檢視、查詢資料存放區支援之作業類型的能力,以及視需要載入資料的功能。

  • 對泛型 IEnumerableIListSource 介面的資料來源支援。

  • 對資料繫結運算式的支援,能使網頁開發人員在控制項的公開 (Expose) 又特別標記的屬性與資料來源之間建立繫結。如需資料繫結 (Data Binding) 運算式的詳細資訊,請參閱資料繫結運算式概觀

  • 對自動資料繫結的支援,會盡可能在網頁生命週期的最後階段而且只在需要時 (而非在每一次回傳時),才叫用 (Invoke) 資料繫結邏輯。在網頁執行完第一次資料繫結要求之後,其後的要求便會試圖從檢視狀態中擷取資料。如此,避免了在每一次要求時需要重新連接至資料來源,進而提升效能。

利用可用的設計階段功能

在所有 Web 伺服器控制項中有不少可使用的設計階段功能,讓您可以想要依照自訂資料繫結控制項來做考量。您可以為自訂控制項建立設計工具類別和控制項樣板 (Template),這樣在設計階段於視覺化設計介面 (例如 Visual Studio 中的設計檢視) 上使用該控制項時,便會叫用這些功能。

藉由提供能使網頁開發人員自訂控制項屬性的設計階段介面,建立控制項設計工具就可以讓自訂控制項在設計階段充分發揮作用。如需 ASP.NET 控制項設計工具的概觀,請參閱 ASP.NET 控制項設計工具概觀。如需範例,請參閱 HierarchicalDataBoundControlDesigner逐步解說:建立 Web 伺服器控制項的基本控制項設計工具

藉由建立樣板化的控制項,您讓網頁開發人員可以彈性指定定義控制項之使用者介面的控制項和標記。如需自訂樣板化的控制項之範例,請參閱樣板化伺服器控制項範例

在 ASP.NET 2.0 中實作自訂資料繫結控制項

下表概括了在 ASP.NET 2.0 中實作自訂資料繫結伺服器控制項的特定步驟。您可以在表格之後的內容找到每一個實作步驟的詳細資訊。

步驟

步驟摘要

選擇資料繫結控制項基底類別

擴充已有許多所需之功能的現有資料繫結控制項,或是自其中一個資料繫結控制項基底類別衍生。

公開資料繫結屬性

將自訂控制項設為不但公開由資料繫結控制項基底類別公開的最少必要資料繫結屬性,還公開其他資料繫結屬性。

啟始資料擷取

  • 藉由執行下列各項,擷取網頁開發人員已指派給控制項的資料:

  • 覆寫資料繫結控制項基底類別的 PerformSelect 方法。

  • 呼叫資料繫結控制項基底類別的 GetData 方法,擷取控制項的資料來源檢視。

  • 呼叫 DataSourceView 物件的 Select 方法啟始資料擷取,並指定將接收資料的回呼 (Callback) 方法。

處理已擷取的資料

提供 Select 方法中您指定做為參數的回呼方法。回呼方法必須具備 IEnumerable 型別的單一參數,才能接收資料。如果控制項需要處理任何資料,則必須在這個回呼方法內發生。

建立表示資料的 UI 物件

提供 PerformDataBinding 方法的覆寫。您必須在這個方法內執行下列工作:

  • 呼叫 PerformDataBinding 方法,讓任何依賴這個方法的其他程式碼執行。

  • 逐一列舉資料集合,並建立任何將以 UI 顯示方式表示資料的子控制項。

選擇資料繫結控制項基底類別

控制項開發人員可以將其中一個可用的資料繫結控制項基底類別擴充,建立自訂資料繫結控制項。下表提供 ASP.NET 2.0 中可用的資料繫結基底類別。請先行檢閱每個類別的說明,再決定最符合您自訂資料繫結控制項需求的基底類別。如需每個適用於資料繫結控制項之基底類別與實作範例的詳細資訊,請參閱各個類別的參考文件。如需 ASP.NET 提供之資料繫結控制項的詳細資訊,請參閱 ASP.NET 資料繫結 Web 伺服器控制項概觀

類別

說明

BaseDataBoundControl

  • 此為所有資料繫結控制項的基底類別,可對任何繫結資料執行資料繫結與驗證。

DataBoundControl

此為建置 (Build) 標準資料繫結控制項的資料繫結基底類別。DataBoundControl 可以進行下列各項:

  • 提供所有資料繫結控制項共用的基本實作。

  • 包含要與資料來源控制項和資料容器 (Container) 通訊的邏輯。

  • 做為資料繫結控制項的基礎,例如 TreeViewListControl

ListControl

  • 此為清單控制項的基底類別,並可擴充 DataBoundControl 類別。它提供 Items 集合和進階配置呈現能力。

CompositeDataBoundControl

  • 此為擴充 DataBoundControl 類別的基底類別,提供以下功能:

  • 實作複合控制項 (Composite Control) 所需的一般程式碼,包括在發生回傳後自檢視狀態中還原控制項的子控制項階層架構。

  • 繫結至 IEnumerable 資料來源,並列舉要建置控制項樹狀結構的資料。

  • 做為資料繫結控制項的基礎,例如 GridViewDetailsView

HierarchicalDataBoundControl

  • 此為以階層形式顯示資料的控制項之基底類別。它可做為資料繫結樹狀結構式控制項的基礎,例如 TreeViewMenu

提供的資料繫結屬性

資料繫結控制項基底類別提供了公開的資料繫結屬性,為要讓網頁開發人員將資料來源繫結至控制項,就需要有這些屬性。但對控制項作者所負責部分則不需要做額外的處理。藉由衍生自 DataBoundControl,例如自訂控制項便會繼承三個公開的資料繫結屬性:DataSourceIDDataSourceDataMember,然後網頁開發人員就可以透過設定 DataSourceDataSourceID 屬性的值來指定控制項將繫結的資料來源。

DataSourceID 屬性可以讓網頁開發人員指定表示資料繫結控制項所擷取資料之資料來源的控制項 ID。

DataSource 屬性可以讓網頁開發人員將資料繫結控制項直接繫結至以下兩種資料物件:

  • 實作 IEnumerable 介面的物件,例如 ArrayArrayListHashtable 物件。

  • 實作 IListSource 介面的物件,例如 DataSet 物件。

  • 其他資料繫結屬性,例如 DataMember 屬性,則可以讓網頁開發人員指定控制項應該繫結的一部分資料集合。

  • 如需由每個資料繫結控制項類別或資料繫結控制項基底類別提供的公開資料繫結屬性,請參閱各個類別的參考文件。

公開自訂資料繫結屬性

當您在自訂控制項中公開自己的自訂資料繫結屬性,或是覆寫現有資料繫結屬性時,如果控制項已經初始化,就必須呼叫 OnDataPropertyChanged 方法。這個動作會強制資料繫結控制項重新繫結資料,如此它才可以使用新的資料繫結屬性設定。

下列程式碼範例將示範屬於衍生資料繫結控制項類別的屬性。這個範例將示範資料繫結控制項在初始化後,如果識別資料來源的屬性發生變更,如何能呼叫 OnDataPropertyChanged 方法。

Inherits DataBoundControl

Public Property DataTextField() As String
    Get
        Dim o As Object = ViewState("DataTextField")
        If o Is Nothing Then
            Return String.Empty
        Else
            Return CStr(o)
        End If
    End Get
    Set(ByVal value As String)
        ViewState("DataTextField") = value
        If (Initialized) Then
            OnDataPropertyChanged()
        End If
    End Set
End Property
public class SimpleDataBoundColumn : DataBoundControl
{
    public string DataTextField
    {
        get
        {
            object o = ViewState["DataTextField"];
            return ((o == null) ? string.Empty : (string)o);
        }
        set
        {
            ViewState["DataTextField"] = value;
            if (Initialized)
            {
                OnDataPropertyChanged();
            }
        }
    }

啟始資料擷取

資料擷取是在控制項的基底資料繫結控制項所繼承之 PerformSelect 方法的覆寫內啟始的。在這個覆寫內,您可以呼叫擷取資料,並指定會在資料傳回後進行處理的回呼方法。

若要擷取資料,請在覆寫的 PerformSelect 方法中完成下列工作:

  1. 判斷網頁開發人員是否使用了 DataSource 屬性或 DataSourceID 屬性,將資料設為繫結至控制項。這只要驗證 IsBoundUsingDataSourceID 屬性就行了。例如,IsBoundUsingDataSourceID 屬性的 false 設定值表示已使用 DataSource 屬性來指定資料來源。

  2. 如果網頁開發人員設定了 DataSource 屬性,則必須進行額外的步驟:呼叫 OnDataBinding 方法。

  3. 呼叫 GetData 方法,擷取與資料繫結控制項關聯的 DataSourceView 物件。

  4. 呼叫已擷取的 DataSourceViewSelect 方法啟始資料擷取,並指定將處理已擷取之資料的回呼方法。Select 方法會以非同步方式作業,因此在擷取資料時也可以進行其他處理。

  5. RequiresDataBinding 屬性設為 false 再呼叫 MarkAsDataBound 方法,便表示完成 PerformSelect 工作。

  6. 引發 OnDataBound 事件。

下列程式碼範例將說明前面的擷取工作在 PerformSelect 方法的覆寫內標示為完成。

Protected Overrides Sub PerformSelect()
    ' Call OnDataBinding here if bound to a data source using the
    ' DataSource property (instead of a DataSourceID), because the
    ' databinding statement is evaluated before the call to GetData.       
    If Not IsBoundUsingDataSourceID Then
        OnDataBinding(EventArgs.Empty)
    End If

    ' The GetData method retrieves the DataSourceView object from  
    ' the IDataSource associated with the data-bound control.            
    GetData().Select(CreateDataSourceSelectArguments(), _
        AddressOf OnDataSourceViewSelectCallback)

    ' The PerformDataBinding method has completed.
    RequiresDataBinding = False
    MarkAsDataBound()

    ' Raise the DataBound event.
    OnDataBound(EventArgs.Empty)

End Sub
protected override void PerformSelect()
{
    // Call OnDataBinding here if bound to a data source using the
    // DataSource property (instead of a DataSourceID), because the
    // databinding statement is evaluated before the call to GetData.       
    if (!IsBoundUsingDataSourceID)
    {
        this.OnDataBinding(EventArgs.Empty);
    }

    // The GetData method retrieves the DataSourceView object from  
    // the IDataSource associated with the data-bound control.            
    GetData().Select(CreateDataSourceSelectArguments(),
        this.OnDataSourceViewSelectCallback);

    // The PerformDataBinding method has completed.
    RequiresDataBinding = false;
    MarkAsDataBound();

    // Raise the DataBound event.
    OnDataBound(EventArgs.Empty);
}

處理已擷取的資料。

您可以建立自己的呼回方法來接受已擷取的資料。在 PerformSelect 方法的覆寫內呼叫 Select 方法,即為指定回呼方法的方式。回呼方法只需要包含 IEnumerable 型別的單一參數。如果控制項需要的話,您可以在回呼方法中對傳回的資料進行任何處理。最後,則是呼叫 PerformDataBinding 方法。

下列程式碼範例將說明回呼方法,它具有 IEnumerable 型別的參數,並呼叫 PerformDataBinding 方法。

Private Sub OnDataSourceViewSelectCallback(ByVal retrievedData As IEnumerable)
    ' Call OnDataBinding only if it has not already been 
    ' called in the PerformSelect method.
    If IsBoundUsingDataSourceID Then
        OnDataBinding(EventArgs.Empty)
    End If
    ' The PerformDataBinding method binds the data in the  
    ' retrievedData collection to elements of the data-bound control.
    PerformDataBinding(retrievedData)

End Sub
private void OnDataSourceViewSelectCallback(IEnumerable retrievedData)
{
    // Call OnDataBinding only if it has not already been 
    // called in the PerformSelect method.
    if (IsBoundUsingDataSourceID)
    {
        OnDataBinding(EventArgs.Empty);
    }
    // The PerformDataBinding method binds the data in the  
    // retrievedData collection to elements of the data-bound control.
    PerformDataBinding(retrievedData);
}

建立表示資料的 UI 物件

PerformDataBinding 方法的覆寫內,您會建立表示資料的子控制項,也會列舉資料集合,並建立子控制項且根據每個資料項目設定其屬性。藉由將新的子控制項加入至控制項的 Controls 集合,即可呈現子控制項。在控制項之繼承的 Render 方法期間,會呈現控制項階層架構。您可以選擇覆寫 Render 方法,執行自訂控制項所需的特殊呈現效果,例如包含其他 HTML 項目或是在設計模式時顯示特殊呈現效果。

若要建立表示資料的 UI 物件,請覆寫 PerformDataBinding 方法並完成下列工作:

  1. 呼叫 PerformDataBinding 方法,讓任何依賴這個方法的其他程式碼執行。

  2. 逐一列舉資料集合,並建立任何將以 UI 顯示方式表示資料的子控制項。呼叫控制項的 Add 方法,將每個子控制項加入至控制項的集合。

  • 下列程式碼範例將說明覆寫 PerformDataBinding 方法。這個 PerformDataBinding 方法會被呼叫,使任何依賴這個方法的其他程式碼得以執行。而且會列舉資料集合,並建立以 UI 顯示方式表示該資料的子控制項。
        Protected Overrides Sub PerformDataBinding(ByVal retrievedData As IEnumerable)
            MyBase.PerformDataBinding(retrievedData)

            ' Verify data exists.
            If Not (retrievedData Is Nothing) Then
                Dim tbl As New Table()
                Dim row As TableRow
                Dim cell As TableCell
                Dim dataStr As String = String.Empty

                Dim dataItem As Object
                For Each dataItem In retrievedData
                    ' If the DataTextField was specified get the data
                    ' from that field, otherwise get the data from the first field. 
                    If DataTextField.Length > 0 Then
                        dataStr = DataBinder.GetPropertyValue(dataItem, DataTextField, Nothing)
                    Else
                        Dim props As PropertyDescriptorCollection = TypeDescriptor.GetProperties(dataItem)
                        If props.Count >= 1 Then
                            If Nothing <> props(0).GetValue(dataItem) Then
                                dataStr = props(0).GetValue(dataItem).ToString()
                            End If
                        End If
                    End If

                    row = New TableRow()
                    tbl.Rows.Add(row)
                    cell = New TableCell()
                    cell.Text = dataStr
                    row.Cells.Add(cell)
                Next dataItem

                Controls.Add(tbl)
            End If

        End Sub
    End Class
End Namespace
protected override void PerformDataBinding(IEnumerable retrievedData)
{
    base.PerformDataBinding(retrievedData);

    // Verify data exists.
    if (retrievedData != null)
    {
        Table tbl = new Table();
        TableRow row;
        TableCell cell;
        string dataStr = String.Empty;

        foreach (object dataItem in retrievedData)
        {
            // If the DataTextField was specified get the data
            // from that field, otherwise get the data from the first field. 
            if (DataTextField.Length > 0)
            {
                dataStr = DataBinder.GetPropertyValue(dataItem,
                    DataTextField, null);
            }
            else
            {
                PropertyDescriptorCollection props =
                        TypeDescriptor.GetProperties(dataItem);
                if (props.Count >= 1)
                {
                    if (null != props[0].GetValue(dataItem))
                    {
                        dataStr = props[0].GetValue(dataItem).ToString();
                    }
                }
            }

            row = new TableRow();
            tbl.Rows.Add(row);
            cell = new TableCell();
            cell.Text = dataStr;
            row.Cells.Add(cell);
        }

        this.Controls.Add(tbl); 
    }
}

建置自訂伺服器控制項

如需建置自訂資料繫結 Web 伺服器控制項並加以用於 Web 網頁的詳細資訊,請參閱建置自訂伺服器控制項範例

請參閱

工作

逐步解說:建立 ASP.NET 2.0 的自訂資料繫結 ASP.NET Web 控制項

逐步解說:開發和使用自訂的伺服器控制項

概念

ASP.NET 資料繫結 Web 伺服器控制項概觀

自訂伺服器控制項的中繼資料屬性

ASP.NET 控制項設計工具概觀

參考

HierarchicalDataBoundControlDesigner

其他資源

開發自訂的 ASP.NET 伺服器控制項