GridViewで同一値のセルを結合して表示する

GridViewでセルを結合するサンプルです。
このサンプルでは複数行で同一値が繰り返し表示される部分を、縦方向にセルを結合する例です。


バインドするデータ(結合なし)↓


ここで、製品カテゴリ「Clothing」や「Bikes」、サブカテゴリの「Bib-Shorts」、「Mountain Bikes」、「Road Bikes」の連続した同一値のセルが表示されている部分を、ひとつのセルでまとめて表示してみます。

以下、サンプルコード。

GridView2.aspx から一部抜粋


HeaderStyle-Font-Bold="true"
HeaderStyle-BackColor="#f0f0ff"
>



Text='<%# DataBinder.Eval(Container.DataItem, "製品カテゴリ") %>' >






Text='<%# DataBinder.Eval(Container.DataItem, "サブカテゴリ") %>' >






Text='<%# DataBinder.Eval(Container.DataItem, "製品名") %>' >




GridView2.aspx.cs


using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class test_GridView2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//RowDataBoundイベントハンドラを設定
this.GridView1.RowDataBound += GridView1_RowDataBound;
if (!IsPostBack)
{
//サンプルデータをGridViewに表示
this.GridView1.DataSource = getdummydata();
this.GridView1.DataBind();
}
}

//前行の製品カテゴリの確保用
private string PreProductCategory;
private string PreProductSubCategory;
//カテゴリセルの確保用
private TableCell CellProductCategory;
private TableCell CellProductSubCategory;

//GridViewの行バインドイベント
//ここで、バインドデータが前行と同じ値の場合、前行のセルのRowSpanをインクリメントし、現在の行のセルのVisibleをfalseにする処理を行います。
protected void GridView1_RowDataBound
(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//現在の行のカテゴリ名を取得
string ProductCategory =
(string)DataBinder.Eval(e.Row.DataItem, "製品カテゴリ");
string ProductSubCategory =
(string)DataBinder.Eval(e.Row.DataItem, "サブカテゴリ");

//製品カテゴリのセルの処理(e.Row.Cells[0]のセルは、製品カテゴリのセルを表します)
if (ProductCategory == PreProductCategory)
{
//前行と同じ製品カテゴリ
if (CellProductCategory != null)
{
//この行のセルを非表示にする
e.Row.Cells[0].Visible = false;
//確保していたセルのRowSpanをインクリメント(初期値は0のため、0の場合は2をセット)
if (CellProductCategory.RowSpan == 0)
{
CellProductCategory.RowSpan = 2;
}
else
{
CellProductCategory.RowSpan++;
}
}
}else{
//新しい製品カテゴリ。セルを確保
CellProductCategory = e.Row.Cells[0];
}

//サブカテゴリのセルの処理(e.Row.Cells[1]のセルは、サブカテゴリのセルを表します)
if (ProductSubCategory == PreProductSubCategory)
{
//前行と同じサブカテゴリ
if (CellProductSubCategory != null)
{
//この行のセルを非表示にする
e.Row.Cells[1].Visible = false;
//確保していたセルのRowSpanをインクリメント(初期値は0のため、0の場合は2をセット)
if (CellProductSubCategory.RowSpan == 0)
{
CellProductSubCategory.RowSpan = 2;
}
else
{
CellProductSubCategory.RowSpan++;
}
}
}
else
{
//新しいサブカテゴリ。セルを確保
CellProductSubCategory = e.Row.Cells[1];
}

//この行のカテゴリ名を確保
PreProductCategory = ProductCategory;
PreProductSubCategory = ProductSubCategory;
}
}


///


/// 初回の表示データを取得する
///

///
private DataTable getdummydata()
{
DataTable dt = new DataTable();
dt.Columns.Add("製品カテゴリ", typeof(string));
dt.Columns.Add("サブカテゴリ", typeof(string));
dt.Columns.Add("製品名", typeof(string));
//AdventureWorksのDBから適当なサンプルデータを用意
dt.Rows.Add(new String { "Clothing", "Bib-Shorts", "Men's Bib-Shorts, M" });
dt.Rows.Add(new String
{ "Clothing", "Bib-Shorts", "Men's Bib-Shorts, S" });
dt.Rows.Add(new String { "Clothing", "Caps", "AWC Logo Cap" });
dt.Rows.Add(new String
{ "Bikes", "Mountain Bikes", "Mountain-500 Silver, 48" });
dt.Rows.Add(new String { "Bikes", "Mountain Bikes", "Mountain-500 Silver, 52" });
dt.Rows.Add(new String
{ "Bikes", "Road Bikes", "Road-150 Red, 44" });
dt.Rows.Add(new String { "Bikes", "Road Bikes", "Road-150 Red, 48" });
dt.Rows.Add(new String
{ "Bikes", "Road Bikes", "Road-150 Red, 52" });
return dt;
}
}

上記を実行すると、こんな感じで表示されます。


ちなみに、横に結合したい場合でも、ColSpanを調整すれば今回と似たような手法で実現できます。