.NET TIPS

DataGridViewコントロールの連続する同じ値のセルを1つにまとめるには?[2.0のみ、C#、VB]

デジタルアドバンテージ 遠藤 孝信
2007/05/17

 DataGridViewコントロールでは、同じ内容のセルが連続して並ぶ場合に、それらを1つのセルにまとめることにより表示を見やすくできる。以下の画面は通常の表示(上)と同じセルを1つにまとめた場合の表示(下)の例である。

[通常の表示]


[同じセルをまとめた場合の表示]

連続する同じ内容のセルを1つのセルにまとめたDataGridViewコントロール(下)

 このような表示は、不要なセルの値と境界線を消すことにより実現できる。本稿では、次のような手順によりこれを実装している。

  1. セルの値が1つ上のセルと同じであれば、その値を空文字に置き換える

  2. すべてのセルにおいて下側の境界線を描画しない

  3. セルの値が1つ上のセルと同じであれば、そのセルの上側の境界線を描画しない

 1.のセルの値を書き換える処理は、セルが表示される直前にセルごとに発生するCellFormattingイベントのタイミングで行うことができる。また、2.と3.のセルの境界線の描画設定については、セルの描画時にセルごとに発生するCellPaintingイベントのタイミングで行える。どちらのイベントにおいても、イベント・ハンドラに渡されるパラメータから、現在処理中のセルの位置を知ることができる。

 まず以下に、これらの手順を実装したサンプル・プログラムを示す。上記の画面はそのサンプル・プログラムの実行例である。

連続する同じ内容のセルを1つのセルにまとめるサンプル・プログラム

 このサンプル・プログラムでは、DataGridViewコントロールに表示するデータとして、@ITの新着記事についてのRSS情報(RSS 2.0)を使用している。プログラムでは、このRSS情報から、記事の公開日、公開しているフォーラム、記事タイトルのみをグリッドに表示する。RSS情報の取得とDataGridViewコントロールの初期化は、フォームのLoadイベント・ハンドラで行っている。

// dgvgroupedcell.cs

using System;
using System.Data;
using System.Drawing;
using System.Windows.Forms;

public class MyForm : Form {

  DataGridView dgv;

  // 指定したセルと1つ上のセルの値を比較
  bool IsTheSameCellValue(int column, int row) {

    DataGridViewCell cell1 = dgv[column, row];
    DataGridViewCell cell2 = dgv[column, row - 1];

    if (cell1.Value == null || cell2.Value == null) {
      return false;
    }

    // ここでは文字列としてセルの値を比較
    if (cell1.Value.ToString() == cell2.Value.ToString()) {
      return true;
    } else {
      return false;
    }
  }

  // DataGridViewのCellFormattingイベント・ハンドラ
  void dgv_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) {

    // 1行目については何もしない
    if (e.RowIndex == 0)
      return;

    if (IsTheSameCellValue(e.ColumnIndex, e.RowIndex)) {
      e.Value = "";
      e.FormattingApplied = true; // 以降の書式設定は不要
    }
  }

  // DataGridViewのCellPaintingイベント・ハンドラ
  void dgv_CellPainting(object sender, DataGridViewCellPaintingEventArgs e) {

    // セルの下側の境界線を「境界線なし」に設定
    e.AdvancedBorderStyle.Bottom = DataGridViewAdvancedCellBorderStyle.None;

    // 1行目や列ヘッダ、行ヘッダの場合は何もしない
    if (e.RowIndex < 1 || e.ColumnIndex < 0)
      return;

    if (IsTheSameCellValue(e.ColumnIndex, e.RowIndex)) {
      // セルの上側の境界線を「境界線なし」に設定
      e.AdvancedBorderStyle.Top = DataGridViewAdvancedCellBorderStyle.None;
    } else {
      // セルの上側の境界線を既定の境界線に設定
      e.AdvancedBorderStyle.Top = dgv.AdvancedCellBorderStyle.Top;
    }
  }

  // フォームのLoadイベント・ハンドラ
  void MyForm_Load(object sender, EventArgs e) {

    // @ITのRSS情報をデータセットに読み込む
    DataSet ds = new DataSet();
    ds.ReadXml("http://rss.rssad.jp/rss/itm/rss.xml");

    // 3つの列(公開日、フォーラム、タイトル)のみを表示
    dgv.ColumnCount = 3;
    dgv.Columns[0].DataPropertyName = "pubDate";
    dgv.Columns[0].HeaderText = "公開日";
    dgv.Columns[1].DataPropertyName = "category";
    dgv.Columns[1].HeaderText = "フォーラム";
    dgv.Columns[2].DataPropertyName = "title";
    dgv.Columns[2].HeaderText = "記事タイトル";

    // 列の自動生成を行わない
    dgv.AutoGenerateColumns = false;

    // RSS内の<item>要素部分をデータソースとして使用
    dgv.DataSource = ds.Tables["item"];
  }

  // フォームのコンストラクタ
  public MyForm() {
    dgv = new DataGridView();
    dgv.Dock = DockStyle.Fill;
    dgv.CellFormatting += new DataGridViewCellFormattingEventHandler(dgv_CellFormatting);
    dgv.CellPainting += new DataGridViewCellPaintingEventHandler(dgv_CellPainting);
    this.Controls.Add(dgv);
    this.Size = new Size(480, 240);
    this.Load += new EventHandler(MyForm_Load);
  }
}

class Program {
  [STAThread]
  static void Main() {
    Application.Run(new MyForm());
  }
}

// コンパイル方法:csc dgvgroupedcell.cs
連続する同じ内容のセルを1つのセルにまとめるC#のサンプル・プログラム(dgvgroupedcell.cs)

' dgvgroupedcell.vb

Imports System
Imports System.Data
Imports System.Drawing
Imports System.Windows.Forms

Public Class MyForm
    Inherits Form

  WithEvents dgv As DataGridView

  ' 指定したセルと1つ上のセルの値を比較
  Function IsTheSameCellValue(ByVal column As Integer, ByVal row As Integer) As Boolean

    Dim cell1 As DataGridViewCell = dgv(column, row)
    Dim cell2 As DataGridViewCell = dgv(column, row - 1)

    If cell1.Value = Nothing Or cell2.Value = Nothing Then
      Return False
    End If

    ' ここでは文字列としてセルの値を比較
    If cell1.Value.ToString() = cell2.Value.ToString() Then
      Return True
    Else
      Return False
    End If

  End Function

  ' DataGridViewのCellFormattingイベント・ハンドラ
  Sub dgv_CellFormatting(sender As Object, e As DataGridViewCellFormattingEventArgs) Handles dgv.CellFormatting

    ' 1行目については何もしない
    If e.RowIndex = 0 Then
      Return
    End If

    If IsTheSameCellValue(e.ColumnIndex, e.RowIndex) Then
      e.Value = ""
      e.FormattingApplied = true ' 以降の書式設定は不要
    End If
  End Sub

  ' DataGridViewのCellPaintingイベント・ハンドラ
  Sub dgv_CellPainting(sender As Object, e As DataGridViewCellPaintingEventArgs) Handles dgv.CellPainting

    ' セルの下側の境界線を「境界線なし」に設定
    e.AdvancedBorderStyle.Bottom = DataGridViewAdvancedCellBorderStyle.None

    ' 1行目や列ヘッダ、行ヘッダの場合は何もしない
    If e.RowIndex < 1 Or e.ColumnIndex < 0 Then
      Return
    End If

    If IsTheSameCellValue(e.ColumnIndex, e.RowIndex) Then
      ' セルの上側の境界線を「境界線なし」に設定
      e.AdvancedBorderStyle.Top = DataGridViewAdvancedCellBorderStyle.None
    Else
      ' セルの上側の境界線を既定の境界線に設定
      e.AdvancedBorderStyle.Top = dgv.AdvancedCellBorderStyle.Top
    End If
  End Sub

  ' フォームのLoadイベント・ハンドラ
  Sub MyForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load

    ' @ITのRSS情報をデータセットに読み込む
    Dim ds As New DataSet()
    ds.ReadXml("http://rss.rssad.jp/rss/itm/rss.xml")

    ' 3つの列(公開日、フォーラム、タイトル)のみを表示
    dgv.ColumnCount = 3
    dgv.Columns(0).DataPropertyName = "pubDate"
    dgv.Columns(0).HeaderText = "公開日"
    dgv.Columns(1).DataPropertyName = "category"
    dgv.Columns(1).HeaderText = "フォーラム"
    dgv.Columns(2).DataPropertyName = "title"
    dgv.Columns(2).HeaderText = "記事タイトル"

    ' 列の自動生成を行わない
    dgv.AutoGenerateColumns = False

    ' RSS内の<item>要素部分をデータソースとして使用
    dgv.DataSource = ds.Tables("item")
  End Sub

  ' フォームのコンストラクタ
  Public Sub New()
    dgv = New DataGridView()
    dgv.Dock = DockStyle.Fill
    Me.Controls.Add(dgv)
    Me.Size = new Size(480, 240)
  End Sub
End Class

' コンパイル方法:vbc /main:MyForm dgvgroupedcell.vb
連続する同じ内容のセルを1つのセルにまとめるVBのサンプル・プログラム(dgvgroupedcell.vb)

 プログラムの最初にあるIsTheSameCellValueメソッドは、縦に並んだ2つのセルの値が同じかどうかをチェックするためのものだ。

 CellFormattingイベント・ハンドラでは、イベントの発生したセルと、その1つ上のセルの値が同じであれば、セルの値を空白文字に置き換えている。このイベントについては「TIPS:DataGridViewコントロールで特定の値のセルを強調表示するには?」でも解説しているので参考にしてほしい。

 セルの描画時に呼び出されるCellPaintingイベント・ハンドラでは、そのメソッドに渡されるDataGridViewCellPaintingEventArgsクラス(System.Windows.Forms名前空間)のオブジェクトのAdvancedBorderStyleプロパティにより、個々のセルにおける上下左右の境界線の描画のスタイルを指定できる。

 DataGridViewコントロールのAdvancedCellBorderStyleプロパティでもセルの境界線スタイルを変更できるが、セルごとに個別の境界線スタイルを指定したい場合には、CellPaintingイベント・ハンドラを利用する必要がある。

 なお、本来ならばCellPaintingイベントの発生しているセルの上側の境界線スタイルと、その1つ上のセルの下側の境界線スタイルを「境界線なし」にしたいところだが、コード中の で、すべてのセルについて下側の境界線を「境界線なし」に設定しているのは、イベントの発生していないセルの境界線スタイルを変更できないためである。

 また、 の行は本来不要なはずだが、 で下側の境界線を消してしまうとその1つ下のセルの上側の境界線も消えてしまうため(つまりすべての横線が消える)、CellPaintingイベントの発生しているセルと1つ上のセルと値が異なる場合には、 によりセルの上側の境界線が描画されるようにしている。このため実際には、 の行がなくても表示は変わらない。End of Article

利用可能バージョン:.NET Framework 2.0のみ
カテゴリ:Windowsフォーム 処理対象:DataGridViewコントロール
使用ライブラリ:DataGridViewコントロール
使用ライブラリ:DataGridViewCellPaintingEventArgsクラス(System.Windows.Forms名前空間)
関連TIPS:DataGridViewコントロールで特定の値のセルを強調表示するには?

この記事と関連性の高い別の.NET TIPS
DataGridViewコントロールで特定の値のセルを強調表示するには?
[ASP.NET]DataGridコントロールのヘッダーを結合するには?
[ASP.NET]DataGridコントロールの同一列内のセルを結合するには?
DataGridViewコントロールで右クリックによるセル選択を可能にするには?
DataGridViewコントロールで選択されている行やセルを調べるには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」

@IT Special

- PR -

TechTargetジャパン

Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

イベントカレンダー

PickUpイベント

- PR -

アクセスランキング

もっと見る

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

注目のテーマ

Insider.NET 記事ランキング

本日 月間
ソリューションFLASH