次の方法で共有


template 宣言のあるデータ連結コントロールの開発

ASP.NET データ連結構文を使用して、コントロールのプロパティを単一のデータ項目または式に連結するのは簡単です。ここでは、System.Collections.ICollection コレクション型または System.Collections.IEnumerable コレクション型であるデータ ソースに連結された template 宣言のあるプロパティを備えたコントロール開発の、より複雑なシナリオについて説明します。テンプレートを使用すると、ページ開発者は、コントロールに連結されたデータのプレゼンテーションをカスタマイズできます。Repeater および DataList コントロールは、template 宣言のあるデータ連結コントロールの例です。

ASP.NET ページでのデータ連結の概要については、「ASP.NET クイック スタート」の「.NET サンプル - ASP.NET のデータ連結」でデータ連結のサンプルを参照してください。template 宣言のあるコントロール作成のバックグラウンドについては、「テンプレート コントロールの開発」を参照してください。

template 宣言のあるデータ連結コントロールは、ICollection 型または IEnumerable 型のデータ ソース プロパティを 1 つと ITemplate 型のプロパティを 1 つ以上備えています。テンプレート プロパティのコンテナは、データ連結先のプロパティ (通常は DataItem という名前) を定義します。template 宣言のあるデータ連結コントロールは、Control から継承した Databind メソッドにデータ連結ロジックを実装します。template 宣言のあるデータ連結コントロールは、ポストバック時に CreateChildControls メソッドをオーバーライドして子コントロールの階層を再作成します。これらの手順の詳細を次に説明します。

template 宣言のあるデータ連結コントロールを開発するには、次のようにします。

  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. Control から継承した DataBind メソッドをオーバーライドしてデータ連結ロジックを提供します。これは、次の手順から構成されます。

    1. 基本クラスの OnDataBinding メソッドを呼び出して、コントロールのデータ連結式を評価する、ページによって追加されたハンドラを呼び出します。
    2. Controls コレクションをクリアします。
    3. 子コントロールの ViewState をクリアします。
    4. データ ソースを使用して子コントロールを作成します。
    5. ASP.NET ページ フレームワークに通知してコントロールの ViewState を追跡します。

    これらの手順を実行するコードを次に示します。CreateChildControlsHierarchy は、子コントロール作成の実際の作業を行うヘルパ メソッドです。詳細については、手順 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 によって、データ ソースと保存されたビューステートをそれぞれ使用して、コントロール階層が作成されます。コントロールは、ダミー データ ソースにより、これら 2 つの手順の共通要素の単一コード パスを実装できます。

    メモ   この手順 (手順 5) では、.NET Framework のデータ連結 ASP.NET コントロールが使用する実装の詳細について説明しています。次のコード片に示す 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
    

    テンプレートの作成とデータ ソースへの DataItem プロパティの連結の実際の作業は、CreateItem メソッドが行います。「template 宣言のあるデータ連結コントロールのサンプル」における 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
    

このトピックで説明した手順を実装するデータ連結コントロールのサンプルについては、「template 宣言のあるデータ連結コントロールのサンプル」を参照してください。

参照

template 宣言のあるデータ連結コントロールのサンプル