共用方式為


開發樣板化的資料繫結控制項

使用 ASP.NET 資料繫結 (Data Binding) 語法可以很容易地將控制項的屬性繫結於單一的資料項目 (或運算式)。本節將說明開發控制項的更複雜案例,其中控制項的樣板屬性所繫結的資料來源是集合型別 (System.Collections.ICollectionSystem.Collections.IEnumerable)。樣板使網頁開發人員可以自訂已繫結於控制項的資料表示方式。RepeaterDataList 控制項是樣板化的資料繫結控制項的範例。

如需 ASP.NET 網頁的資料繫結概觀,請參閱 ASP.NET 快速入門 -> ASP.NET Web Form -> 資料繫結伺服器控制項。如需撰寫樣板控制項的背景資料,請參閱開發樣板化的控制項

樣板化資料繫結控制項具有型別 ICollectionIEnumerable 的資料來源屬性,以及一或多個型別 ITemplate 的屬性。其中一個樣板屬性的容器 (Container) 會定義要繫結資料的屬性 (通常名為 DataItem)。控制項會在繼承自 ControlDatabind 方法中實作它的資料繫結邏輯。它會覆寫 CreateChildControls 方法以重新建立回傳時子控制項的階層架構。這些步驟稍後將詳細說明。

若要開發樣板化的資料繫結控制項

  1. 定義一個會實作 System.Web.UI.INamingContainer 介面的控制項。

    public class TemplatedList : WebControl, INamingContainer {...}
    [Visual Basic]
    Public Class TemplatedList
       Inherits WebControl
       Implements INamingContainer
       ...
    End Class
    
  2. 定義型別 System.Web.UI.ITemplate 的屬性。

    [TemplateContainer(typeof(TemplatedListItem))]
            public virtual ITemplate ItemTemplate {
                get {
                    return itemTemplate;
                }
                set {
                    itemTemplate = value;
                }
            }
    [Visual Basic]
    <TemplateContainer(GetType(TemplatedListItem))> _
    Public Overridable Property ItemTemplate() As ITemplate
       Get
          Return _itemTemplate
       End Get
       Set
          _itemTemplate = value
       End Set
    End Property
    

    樣板 (在 TemplateContainerAttribute 屬性中指定) 的邏輯容器必須擁有要繫結資料的屬性。通常會將這個屬性命名為 DataItem。如需樣板屬性其邏輯容器的詳細資訊,請參閱開發樣板化的控制項。下列範例將定義樣板屬性的容器。

    public class TemplatedListItem : TableRow, INamingContainer {
            private object dataItem;
            public virtual object DataItem {
                get {
                    return dataItem;
                }
                set {
                    dataItem = value;
                }
    }
    [Visual Basic]
    Public Class TemplatedListItem
       Inherits TableRow
       Implements INamingContainer
       Private _dataItem As Object
       Public Overridable Property DataItem() As Object
          Get
             Return _dataItem
          End Get
          Set
             _dataItem = value
          End Set
       End Property
    End Class
    
  3. 覆寫 DataBind 方法 (繼承自 Control) 以提供資料繫結邏輯。這項作業必須完成下列的步驟。

    1. 叫用 (Invoke) 基底類別 (Base Class) 的 OnDataBinding 方法,以叫用處理常式 (由網頁所附加) 來評估控制項上的資料繫結運算式。
    2. 清除 Controls 集合。
    3. 清除子控制項的 ViewState
    4. 建立使用該資料來源的子控制項。
    5. 傳送信號給 ASP.NET 網頁架構以追蹤控制項的 ViewState

    下列程式碼將執行這些步驟。CreateChildControlsHierarchy 是 Helper 方法,它會執行建立子控制項的實際作業。詳細的資訊,請參閱步驟 5。

    public override void DataBind() {
        // Controls with a data-source property perform their 
        // custom data binding by overriding DataBind to
        // evaluate any data-binding expressions on the control    
        // itself.
        base.OnDataBinding(EventArgs.Empty);
    
        // Reset the control's state.
        Controls.Clear();
        ClearChildViewState();
    
        // Create the control hierarchy using the data source.
        CreateControlHierarchy(true);
        ChildControlsCreated = true;
    
        TrackViewState();
    }
    [Visual Basic]
    Public Overrides Sub DataBind()
       ' Controls with a data-source property perform their custom data 
       ' binding by overriding DataBind.
       ' Evaluate any data-binding expressions on the control itself.
       MyBase.OnDataBinding(EventArgs.Empty)
    
       ' Reset the control state.
       Controls.Clear()
       ClearChildViewState()
    
       '  Create the control hierarchy using the data source.
       CreateControlHierarchy(True)
       ChildControlsCreated = True
    
       TrackViewState()
    End Sub
    
  4. 覆寫 CreateChildControls 以重新建立回傳案例中的子控制項。其中包含清除 Controls 集合,並使用檢視狀態 (不使用資料來源) 建立控制項階層架構。建立子控制項的實際工作是隱藏於步驟 5 中的 CreateControlHierarchy 方法。

    protected override void CreateChildControls() {
        Controls.Clear();
    
        if (ViewState["ItemCount"] != null) {
        // Create the control hierarchy using the view state, 
        // not the data source.
        CreateControlHierarchy(false);
        }
    }
    [Visual Basic]
    Protected Overrides Sub CreateChildControls()
       Controls.Clear() 
       If Not (ViewState("ItemCount") Is Nothing) Then
          ' Create the control hierarchy using the view state, 
          ' not the data source.
          CreateControlHierarchy(False)
       End If
    End Sub
    
  5. 定義一個含有 Null 項目的資料來源,並在回傳建立控制項階層架構時使用這個資料來源,而不使用實際的資料來源。步驟 3 和 4 分別使用資料來源和儲存的檢視狀態來建立控制項的階層架構。空的資料來源會使控制項在這兩個步驟的通用項目上實作單一的程式碼路徑。

    注意 這個步驟 (步驟 5) 將說明 .NET Framework 的資料繫結 ASP.NET 控制項所使用的實作 (Implementation) 細節。下列程式碼片段中所顯示的 DummyDataSource 類別和 CreateControlHierarchy 方法並不屬於 .NET Framework 的部份,但仍可由控制項的開發人員來定義。您並不需要實作這些項目;然而,建議您使用這個範例或類似的方法來提供一個通用的程式碼路徑,以用於建立控制項階層架構。

    下列程式碼片段將定義一個空的資料來源。

    internal sealed class DummyDataSource : ICollection {
    
            private int dataItemCount;
    
            public DummyDataSource(int dataItemCount) {
                this.dataItemCount = dataItemCount;
            }
    // Implement other methods of the ICollection interface.
    ...
            public IEnumerator GetEnumerator() {
                return new DummyDataSourceEnumerator(dataItemCount);
            }
    
    
            private class DummyDataSourceEnumerator : IEnumerator {
    
                private int count;
                private int index;
    
                public DummyDataSourceEnumerator(int count) {
                    this.count = count;
                    this.index = -1;
                }
    
    
                public object Current {
                    get {
                        return null;
                    }
                }
    // Define other methods of the IEnumerator interface.
            }
        }
    [Visual Basic]
    NotInheritable Friend Class DummyDataSource
       Implements ICollection
    
       Private dataItemCount As Integer
    
       Public Sub New(dataItemCount As Integer)
          Me.dataItemCount = dataItemCount
       End Sub
    
       ' Implement other methods of the ICollection interface.
       ...
    
       Public Function GetEnumerator() As IEnumerator Implements ICollection.GetEnumerator
          Return New DummyDataSourceEnumerator(dataItemCount)
       End Function
    
       Private Class DummyDataSourceEnumerator
          Implements IEnumerator
    
          Private count As Integer
          Private index As Integer
    
          Public Sub New(count As Integer)
             Me.count = count
             Me.index = - 1
          End Sub
    
          Public ReadOnly Property Current() As Object Implements IEnumerator.Current
             Get
                Return Nothing
             End Get
          End Property
          ' Define other methods of the IEnumerator interface.
          ...
       End Class
    End Class
    

    DummyDataSource 可以用來定義 CreateControlHierarchy 方法,如下所示。

    private void CreateControlHierarchy(bool useDataSource) {
                IEnumerable dataSource = null;
                int count = -1;
    
                if (useDataSource == false) {
                    // ViewState must have a non-null value for ItemCount because this is checked 
                    //  by CreateChildControls.
                    count = (int)ViewState["ItemCount"];
                    if (count != -1) {
                        dataSource = new DummyDataSource(count);
                    }
                }
                else {
                    dataSource = this.dataSource;
                }
    
                if (dataSource != null) {
                    int index = 0;
                    count = 0;
                    foreach (object dataItem in dataSource) {
    ...
    // Invoke a private helper method to create each item. 
                        CreateItem(...);
                        count++;
                        index++;
                    }
                }
    
                if (useDataSource) {
                    // Save the number of items contained for use in round trips.
                    ViewState["ItemCount"] = ((dataSource != null) ? count : -1);
                }
            }
    
    [Visual Basic]
    Private Sub CreateControlHierarchy(useDataSource As Boolean)
       Dim dataSource As IEnumerable = Nothing
       Dim count As Integer = - 1
    
       If useDataSource = False Then
          ' ViewState must have a non-null value for ItemCount because this is checked 
          '  by CreateChildControls.
          count = CInt(ViewState("ItemCount"))
          If count <> - 1 Then
             dataSource = New DummyDataSource(count)
          End If
       Else
          dataSource = Me._dataSource
       End If
    
       If Not (dataSource Is Nothing) Then
          Dim table As New Table()
          Controls.Add(table)
    
          Dim selectedItemIndex As Integer = SelectedIndex
          Dim index As Integer = 0
    
          count = 0
          Dim dataItem As Object
          For Each dataItem In  dataSource
             Dim itemType As ListItemType = ListItemType.Item
             If index = selectedItemIndex Then
                itemType = ListItemType.SelectedItem
             Else
                If index Mod 2 <> 0 Then
                   itemType = ListItemType.AlternatingItem
                End If
             End If 
             CreateItem(table, index, itemType, useDataSource, dataItem)
             count += 1
             index += 1
          Next dataItem
       End If
    
       If useDataSource Then
          ' Save the number of items contained for use in round trips.
          If Not (dataSource Is Nothing) Then
             ViewState("ItemCount") = count
          Else
             ViewState("ItemCount") = -1
          End If
       End If
    End Sub
    

    CreateItem 方法會執行建立樣板和將 DataItem 屬性繫結於資料來源的實際作業。下列的程式碼片段將說明如何在樣板化的資料繫結控制項範例中實作 CreateItem 方法。請注意 CreateItem 方法是一項實作細節且並未在 .NET Framework 中定義。

    private TemplatedListItem CreateItem(Table table, int itemIndex, ListItemType itemType, bool dataBind, object dataItem) {
                TemplatedListItem item = new TemplatedListItem(itemIndex, itemType);
                TemplatedListItemEventArgs e = new TemplatedListItemEventArgs(item);
    
                if (itemTemplate != null) {
                    itemTemplate.InstantiateIn(item.Cells[0]);
                }
                if (dataBind) {
                    item.DataItem = dataItem;
                }
                OnItemCreated(e);
                table.Rows.Add(item);
    
                if (dataBind) {
                    item.DataBind();
                    OnItemDataBound(e);
    
                    item.DataItem = null;
                }
    
                return item;
            }
    [Visual Basic]
    Private Function CreateItem(table As Table, itemIndex As Integer, itemType As ListItemType, dataBind As Boolean, dataItem As Object) As TemplatedListItem
       Dim item As New TemplatedListItem(itemIndex, itemType)
       Dim e As New TemplatedListItemEventArgs(item)
    
       If Not (_itemTemplate Is Nothing) Then
          _itemTemplate.InstantiateIn(item.Cells(0))
       End If
       If dataBind Then
          item.DataItem = dataItem
       End If
       OnItemCreated(e)
       table.Rows.Add(item)
    
       If dataBind Then
          item.DataBind()
          OnItemDataBound(e)
    
          item.DataItem = Nothing
       End If
    
       Return item
    End Function
    

如需實作本主題所描述步驟的資料繫結控制項範例,請參閱樣板化的資料繫結控制項範例

請參閱

樣板化的資料繫結控制項範例