この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
DataGridViewコントロールでは、同じ内容のセルが連続して並ぶ場合に、それらを1つのセルにまとめることにより表示を見やすくできる。以下の画面は通常の表示(上)と同じセルを1つにまとめた場合の表示(下)の例である。
このような表示は、不要なセルの値と境界線を消すことにより実現できる。本稿では、次のような手順によりこれを実装している。
1.のセルの値を書き換える処理は、セルが表示される直前にセルごとに発生するCellFormattingイベントのタイミングで行うことができる。また、2.と3.のセルの境界線の描画設定については、セルの描画時にセルごとに発生するCellPaintingイベントのタイミングで行える。どちらのイベントにおいても、イベント・ハンドラに渡されるパラメータから、現在処理中のセルの位置を知ることができる。
まず以下に、これらの手順を実装したサンプル・プログラムを示す。上記の画面はそのサンプル・プログラムの実行例である。
このサンプル・プログラムでは、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)
// 1行目や列ヘッダ、行ヘッダの場合は何もしない
if (e.RowIndex < 1 || e.ColumnIndex < 0)
return;
if (IsTheSameCellValue(e.ColumnIndex, e.RowIndex)) {
// セルの上側の境界線を「境界線なし」に設定
e.AdvancedBorderStyle.Top = DataGridViewAdvancedCellBorderStyle.None; (2)
} else {
// セルの上側の境界線を既定の境界線に設定
e.AdvancedBorderStyle.Top = dgv.AdvancedCellBorderStyle.Top; (3)
}
}
// フォームのLoadイベント・ハンドラ
void MyForm_Load(object sender, EventArgs e) {
// @ITのRSS情報をデータセットに読み込む
DataSet ds = new DataSet();
ds.ReadXml("http://atmarkit.itmedia.co.jp/rss/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
' 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)
' 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 (2)
Else
' セルの上側の境界線を既定の境界線に設定
e.AdvancedBorderStyle.Top = dgv.AdvancedCellBorderStyle.Top (3)
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
プログラムの最初にあるIsTheSameCellValueメソッドは、縦に並んだ2つのセルの値が同じかどうかをチェックするためのものだ。
CellFormattingイベント・ハンドラでは、イベントの発生したセルと、その1つ上のセルの値が同じであれば、セルの値を空白文字に置き換えている。このイベントについては「TIPS:DataGridViewコントロールで特定の値のセルを強調表示するには?」でも解説しているので参考にしてほしい。
セルの描画時に呼び出されるCellPaintingイベント・ハンドラでは、そのメソッドに渡されるDataGridViewCellPaintingEventArgsクラス(System.Windows.Forms名前空間)のオブジェクトのAdvancedBorderStyleプロパティにより、個々のセルにおける上下左右の境界線の描画のスタイルを指定できる。
DataGridViewコントロールのAdvancedCellBorderStyleプロパティでもセルの境界線スタイルを変更できるが、セルごとに個別の境界線スタイルを指定したい場合には、CellPaintingイベント・ハンドラを利用する必要がある。
なお、本来ならばCellPaintingイベントの発生しているセルの上側の境界線スタイルと、その1つ上のセルの下側の境界線スタイルを「境界線なし」にしたいところだが、コード中の(1)で、すべてのセルについて下側の境界線を「境界線なし」に設定しているのは、イベントの発生していないセルの境界線スタイルを変更できないためである。
また、(3)の行は本来不要なはずだが、(1)で下側の境界線を消してしまうとその1つ下のセルの上側の境界線も消えてしまうため(つまりすべての横線が消える)、CellPaintingイベントの発生しているセルと1つ上のセルと値が異なる場合には、(3)によりセルの上側の境界線が描画されるようにしている。このため実際には、(2)の行がなくても表示は変わらない。
利用可能バージョン:.NET Framework 2.0のみ
カテゴリ:Windowsフォーム 処理対象:DataGridViewコントロール
使用ライブラリ:DataGridViewコントロール
使用ライブラリ:DataGridViewCellPaintingEventArgsクラス(System.Windows.Forms名前空間)
関連TIPS:DataGridViewコントロールで特定の値のセルを強調表示するには?
Copyright© Digital Advantage Corp. All Rights Reserved.