.NET TIPS

[ASP.NET]DataGridコントロールの同一列内のセルを結合するには?

デジタルアドバンテージ
2003/11/28

 DataGridコントロールでデータを一覧表示する場合に、連続する行の同一列内に同じデータが並ぶことがある。少々極端ではあるが、次の画面のような場合である。

連続する行の同一列内に同じデータが並んでいるグリッド

 このようなデータの並びの場合、上下に隣り合って同じデータを表示しているセルを1つのセルに結合することにより、グリッドが見やすくなることがある。これにより例えば上記のグリッドは、次に示す画面のように変更することができる。

同じデータのセルを列単位で結合したグリッド

 本稿では、このような同じデータを持ったセルを列ごとに結合する方法について解説する。

列単位でのセルの結合

 セルの結合についてはすでに「TIPS:[ASP.NET]DataGridコントロールのヘッダーを結合するには?」でも解説している。そちらでは1つの行に含まれるセルを横方向に結合していた。ここでは、それを縦方向に行えばよい。

 つまり、ある列において縦方向に並んでいる複数のセルを1つのセルにするには、それらのセルのうち1つだけ残して残りのセルをすべて削除し、残ったセルが占めるべき行数をそのセルのRowSpanプロパティに指定すればよい。この作業を図示すると次のようになる。

複数のセルを1つのセルに置き換える方法
同じデータを表示しているセルのうち1つだけ残して残りのセルをすべて削除し、残ったセルのRowSpanプロパティにそのセルが占める行数を指定する。

 ここではある程度汎用的に利用できるように、この処理を次のような1つのメソッドとしてまとめてみた。

void joinCells(DataGrid dg, int column) {
  int numRow = dg.Items.Count;
  int baseIndex = 0;

  while (baseIndex < numRow) {
    int nextIndex = baseIndex + 1;
    TableCell baseCell = dg.Items[baseIndex].Cells[column];

    while (nextIndex < numRow) {

      TableCell nextCell = dg.Items[nextIndex].Cells[column];

      if (getText(baseCell) == getText(nextCell)) {
        if (baseCell.RowSpan == 0) {
          baseCell.RowSpan = 2;
        } else {
          baseCell.RowSpan++;
        }
        dg.Items[nextIndex].Cells.Remove(nextCell);
        nextIndex++;
      } else {
        break;
      }
    }
    baseIndex = nextIndex;
  }
}
指定された列で複数のセルを1つのセルに置き換えるjoinCellsメソッド

 このメソッドは、第1パラメータに対象となるDataGridオブジェクトを、第2パラメータにグリッド内の列のインデックス番号を指定して呼び出せばよい。

 セルの削除にはTableCellCollectionクラス(System.Web.UI.WebControls名前空間)のRemoveメソッドを利用している。このメソッドでは、削除対象となっているセルをパラメータで指定する。なお、セルのRowSpanプロパティの初期値は1ではなく0であるという点に少し注意が必要だ。

 セルに表示されているテキストを取り出すためのgetTextメソッドは、このメソッドとは別に記述している。今回のサンプル・プログラムでは列の表示にテンプレート列を使用しているために、このメソッドは次のようになっている。

string getText(TableCell tc) {
  DataBoundLiteralControl dblc =
    (DataBoundLiteralControl)tc.Controls[0];
  return dblc.Text;
}
セルに表示されているテキストを取得するためのgetTextメソッド

 この内容については「TIPS:[ASP.NET]DataGridコントロールでテンプレート列のセルの値を取得するには?」で解説している。

 列を連結列により定義している場合にはこのメソッドは単に「return tc.Text」となるが、2種類の列が混ざっている場合には、それぞれを判別してテキストを返すように変更する必要がある。

同一列内のセルを結合するサンプル・プログラム

 先に示した画面のうち、2つ目の画面を表示するプログラムのソース・コードは次のようになっている。

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>

<html>
<head>
  <script runat="server">
    void Page_Load(object sender, EventArgs e) {
      MyGrid.DataSource = new object[] {
          new object[] {"■", "▲", "■"},
          new object[] {"■", "●", "■"},
          new object[] {"■", "●", "●"},
          new object[] {"■", "■", "●"},
          new object[] {"●", "■", "●"},
          new object[] {"●", "■", "●"},
      };
      MyGrid.DataBind();

      for (int c = 3; c >= 1; c--) {
        joinCells(MyGrid, c);
      }
    }

    string getText(TableCell tc) {
      DataBoundLiteralControl dblc =
        (DataBoundLiteralControl)tc.Controls[0];
      return dblc.Text;
    }

    void joinCells(DataGrid dg, int column) {
      int numRow = dg.Items.Count;
      int baseIndex = 0;

      while (baseIndex < numRow) {
        int nextIndex = baseIndex + 1;
        TableCell baseCell = dg.Items[baseIndex].Cells[column];

        while (nextIndex < numRow) {

          TableCell nextCell = dg.Items[nextIndex].Cells[column];

          if (getText(baseCell) == getText(nextCell)) {
            if (baseCell.RowSpan == 0) {
              baseCell.RowSpan = 2;
            } else {
              baseCell.RowSpan++;
            }
            dg.Items[nextIndex].Cells.Remove(nextCell);
            nextIndex++;
          } else {
            break;
          }
        }
        baseIndex = nextIndex;
      }
    }
  </script>
</head>

<body>
  <form runat="server">
    <asp:DataGrid id="MyGrid"
        AutoGenerateColumns="false"
        ShowHeader="false"
        BackColor="blue"
        CellSpacing="5"
        Width="100%"
        runat="server" >

      <ItemStyle BackColor="white" HorizontalAlign="center" />

      <Columns>
        <asp:TemplateColumn>
          <ItemTemplate>
            <%# Container.ItemIndex + 1 %>
          </ItemTemplate>
        </asp:TemplateColumn>
        <asp:TemplateColumn>
          <ItemTemplate>
            <%# ((object[])Container.DataItem)[0] %>
          </ItemTemplate>
        </asp:TemplateColumn>
        <asp:TemplateColumn>
          <ItemTemplate>
            <%# ((object[])Container.DataItem)[1] %>
          </ItemTemplate>
        </asp:TemplateColumn>
        <asp:TemplateColumn>
          <ItemTemplate>
            <%# ((object[])Container.DataItem)[2] %>
          </ItemTemplate>
        </asp:TemplateColumn>
      </Columns>

    </asp:DataGrid>
  </form>
</body>
</html>
同一列内のセルを結合するC#のサンプル・プログラム(joincells.aspx)

 セルを結合するjoinCellsメソッドを利用するにあたっては、いくつかの注意点がある。このメソッドは、各列に必ず元の行数分のセルが存在しているという前提で記述している。このため、同じDataGridオブジェクトの複数の列に対してこのメソッドを利用する場合には、最も右側にある列から順に適用しなくてはならない。そうしないと列によっては削除しようとしているセルが見つからずにエラーとなることがある。上記のサンプル・プログラムではデータ連結を行った後、joinCellsメソッドを次のようにして呼び出している。

for (int c = 3; c >= 1; c--) {
  joinCells(MyGrid, c);
}

 同じ理由で、このメソッドによってすでにセルの削除を行っている列に繰り返し適用しようとした場合にも、削除しようとしているセルが見つからずにエラーとなることがある。

 また、グリッド内のいずれかの列はセルを結合しないようにしておかないと、データの並びによってはグリッド全体が小さくなってしまう場合があり得る。このため上記のサンプル・プログラムでは、「TIPS:[ASP.NET]DataGridコントロールの行に通し番号を付けるには?」で示した方法により、グリッドの1列目に行番号を表示している。End of Article

カテゴリ:Webフォーム 処理対象:DataGridコントロール
使用ライブラリ:DataGridコントロール
使用ライブラリ:TableCellCollectionクラス(System.Web.UI.WebControls名前空間)
関連TIPS:[ASP.NET]DataGridコントロールのヘッダーを結合するには?
関連TIPS:[ASP.NET]DataGridコントロールでテンプレート列のセルの値を取得するには?
関連TIPS:[ASP.NET]DataGridコントロールの行に通し番号を付けるには?
 
この記事と関連性の高い別の.NET TIPS
[ASP.NET]DataGridコントロールのヘッダーを結合するには?
[ASP.NET]DataGridコントロールの各セルにアクセスするには?
[ASP.NET]DataGridコントロールでテンプレート列のセルの値を取得するには?
[ASP.NET]DataGridコントロールのヘッダーを複数行にするには?
DataGridViewコントロールで特定の値のセルを強調表示するには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」

TechTargetジャパン

Insider.NET フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

キャリアアップ


- PR -

イベントカレンダー

PickUpイベント

- PR -

アクセスランキング

もっと見る
- PR -

ホワイトペーパーTechTargetジャパン

ソリューションFLASH

「ITmedia マーケティング」新着記事

第2回 ヒートマップでLPO――ヒートマップの登場で“in-page web analytics”時代に突入したLPO
ヒートマップがWebサイト分析の現場に登場したことで、LPOは、“in-page web analytics”...

ダウンロードフリー! 「戦略リーダーとしてのマーケティング組織、CMO機能」(eBook版)
「ITmedia マーケティング」編集部では、過去の人気連載をeBook 形式に再編集した新シリ...

第1回 なぜ、いま、DMPなのか?
最近のデジタルマーケティング分野における重要キーワードにDMP(Data Management Platfo...