2007.11.13

ASP.NETでrowspanのある明細表示


列1列2
Aa
Ab
Ba
Bb

このようなデータの列1の重複データをrowspanでまとめて表示したい場合、

列1列2
Aa
b
Ba
b

これをASP.NETで2重構造のRepeaterで実現する方法を紹介する。

■データの取得
まとめる列で集計したデータと、その列に紐づくデータを別々に取得する。 まとめる列には、その明細の行数をカウントしておく。 SQLで例えると
'-- まとめる列の集計クエリ
Select 列1, count(*) rowspan From Table1

'-- 明細のクエリ、まとめる列を含める。
Select 列1, 列2 From Table1
まとめる列のデータ
列1rowspan
A2
B2

紐づく明細のデータ
列1列2
Aa
Ab
Ba
Bb
それぞれ取得したDataTableの列1でDataRelationを作ることにより紐付ける。

■DataTableの作成
    Protected Function GetDataSource() As DataTable

        Dim row As DataRow

        '// リレーションを作るにはDataSetが必要
        Dim ds As New DataSet

        '// まとめる列のDataTable
        Dim dtA As New DataTable
        ds.Tables.Add(dtA)

        dtA.Columns.Add("列1")
        dtA.Columns.Add("rowspan")

        row = dtA.NewRow
        dtA.Rows.Add(row)
        row("列1") = "A"
        row("rowspan") = 2

        row = dtA.NewRow
        dtA.Rows.Add(row)
        row("列1") = "B"
        row("rowspan") = 2

        '// 紐づく明細のDataTable
        Dim dtB As New DataTable
        ds.Tables.Add(dtB)

        dtB.Columns.Add("列1")
        dtB.Columns.Add("列2")

        row = dtB.NewRow
        dtB.Rows.Add(row)
        row("列1") = "A"
        row("列2") = "a"

        row = dtB.NewRow
        dtB.Rows.Add(row)
        row("列1") = "A"
        row("列2") = "b"

        row = dtB.NewRow
        dtB.Rows.Add(row)
        row("列1") = "B"
        row("列2") = "a"

        row = dtB.NewRow
        dtB.Rows.Add(row)
        row("列1") = "B"
        row("列2") = "b"

        '// リレーションの作成
        Dim rel As New DataRelation("relation", dtA.Columns("列1"), dtB.Columns("列1"))
        ds.Relations.Add(rel)

        '// まとめる列のDataTableのみ返せばよい
        Return dtA

    End Function
aspx側には2重構造のリピータを用意する。
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="Default.aspx.vb" Inherits="rowspan._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="https://www.w3.org/1999/xhtml">
<head runat="server">
  <title>rowspan</title>
  <style type="text/css">
    table, th, td { border: 1px solid blue; border-collapse: collapse; text-align: center; }
  </style>
</head>
<body>
  <form id="form1" runat="server">
    <div>
      <asp:Repeater ID="rptData" runat="server">
        <HeaderTemplate>
          <table>
            <tr>
              <th style="width:100px;">
                列1</th>
              <th style="width:100px;">
                列2</th>
            </tr>
        </HeaderTemplate>
        <ItemTemplate>
          <tr>
            <td rowspan="<%# Eval("rowspan") %>">
              <%# Eval("列1") %>
            </td>
            <asp:Repeater ID="rptChild" runat="server" DataSource='<%# GetChildeData(Container.DataItem, "relation") %>'>
              <ItemTemplate>
                <%#IIf(Container.ItemIndex > 0, "<tr>", "")%>
                <td>
                  <%# Eval("列2") %>
                </td>
                </tr>
              </ItemTemplate>
            </asp:Repeater>
        </ItemTemplate>
        <FooterTemplate>
          </table>
        </FooterTemplate>
      </asp:Repeater>
    </div>
  </form>
</body>
</html>
外側のリピータにまとめる列で集計したデータ(dtA)をバインドし、内側のリピータのDataSourceには紐づく明細のデータをバインドする。 リレーション名から明細データを取得するためにGetChildeData関数を用意しておく。
    '// リレーションに紐づくデータを取得
    Protected Function GetChildeData( _
        ByVal obj As Object, _
        ByVal vsRelName As String _
    ) As Data.DataView

        Return DirectCast(obj, Data.DataRowView).CreateChildView(vsRelName)

    End Function
少々ややこしいが、コードおよびデザイン(aspx)はシンプルになると思う。
ただ、同じデータを2回クエリしなければならい負荷は考慮する必要がある。

コメントを投稿

(いままで、ここでコメントしたことがないときは、コメントを表示する前にこのブログのオーナーの承認が必要になることがあります。承認されるまではコメントは表示されません。そのときはしばらく待ってください。)

photo
admin