先ずは列ヘッダーのセルの結合のための定義をコレクションエディターで表示するためにHeaderCellクラスをプロジェクトに追加します。ヘッダーセル定義は以下の項目にします。
VB.NET
C#
Imports System
Imports System.Windows.Forms
Imports System.ComponentModel
Imports System.Drawing
'Public Class HeaderCellColection
' Inherits System.Collections.Generic.List(Of HeaderCell)
'End Class
''' <summary>
''' ヘッダーセル定義
''' </summary>
''' <remarks></remarks>
Public Class HeaderCell
Private _row As Integer
''' <summary>
''' 行
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<Category("セル位置")> _
<Description("行")>
Public Property Row As Integer
Get
Return _row
End Get
Set(ByVal value As Integer)
_row = value
End Set
End Property
Private _column As Integer
''' <summary>
''' 列
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<Category("セル位置")> _
<Description("列")>
Public Property Column As Integer
Get
Return _column
End Get
Set(ByVal value As Integer)
_column = value
End Set
End Property
Private _rowSpan As Integer = 1
''' <summary>
''' 結合する行数
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<Category("セル結合")> _
<Description("行数")>
Public Property RowSpan As Integer
Get
Return _rowSpan
End Get
Set(ByVal value As Integer)
_rowSpan = value
End Set
End Property
Private _columnSpan As Integer = 1
''' <summary>
''' 結合する列数
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<Category("セル結合")> _
<Description("列数")>
Public Property ColumnSpan As Integer
Get
Return _columnSpan
End Get
Set(ByVal value As Integer)
_columnSpan = value
End Set
End Property
Private _backgroundColor As System.Drawing.Color = Color.Empty
''' <summary>
''' セルの背景色
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<Category("表示")> _
<Description("セルの背景色")>
Public Property BackgroundColor As System.Drawing.Color
Get
Return _backgroundColor
End Get
Set(ByVal value As System.Drawing.Color)
_backgroundColor = value
End Set
End Property
Private _foreColor As System.Drawing.Color = Color.Empty
''' <summary>
''' テキストの文字色
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<Category("表示")> _
<Description("テキストの文字色")>
Public Property ForeColor As System.Drawing.Color
Get
Return _foreColor
End Get
Set(ByVal value As System.Drawing.Color)
_foreColor = value
End Set
End Property
Private _text As String
''' <summary>
''' セルに関連付けられたテキスト
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<Category("表示")> _
<Description("セルに関連付けられたテキストです")>
Public Property Text As String
Get
Return _text
End Get
Set(ByVal value As String)
_text = value
End Set
End Property
Private _textAlign As DataGridViewContentAlignment
''' <summary>
''' 結合されたセル内でのテキストの位置
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<Category("表示")> _
<Description("結合されたセル内のテキストの位置を決定します")>
Public Property TextAlign As DataGridViewContentAlignment
Get
Return _textAlign
End Get
Set(ByVal value As DataGridViewContentAlignment)
_textAlign = value
End Set
End Property
Private _wrapMode As DataGridViewTriState = DataGridViewTriState.NotSet
''' <summary>
''' セルに含まれるテキスト形式の内容が 1 行に収まらないほど長い場合に、次の行に折り返されるか、
''' 切り捨てられるかを示す値を取得または設定する
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<Category("表示")> _
<Description("セル内のテキストが一行に収まらない場合にテキストを折り返す")>
Public Property WrapMode As DataGridViewTriState
Get
Return _wrapMode
End Get
Set(ByVal value As DataGridViewTriState)
_wrapMode = value
End Set
End Property
Private _sortVisible As Boolean
''' <summary>
''' 結合されている列に並び替えがある場合に並び替えの方向を表示する
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<Category("表示")> _
<Description("結合されている列に並び替えがある場合に並び替えの方向を表示する")>
Public Property SortVisible As Boolean
Get
Return _sortVisible
End Get
Set(ByVal value As Boolean)
_sortVisible = value
End Set
End Property
End Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Data;
using System.Diagnostics;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;
namespace ClassLibrary1
{
class HeaderCell
{
private int _row;
///
/// 行
///
///
///
///
[Category("セル位置")]
[Description("行")]
public int Row
{
get { return _row; }
set { _row = value; }
}
private int _column;
///
/// 列
///
///
///
///
[Category("セル位置")]
[Description("列")]
public int Column
{
get { return _column; }
set { _column = value; }
}
private int _rowSpan = 1;
///
/// 結合する行数
///
///
///
///
[Category("セル結合")]
[Description("行数")]
public int RowSpan
{
get { return _rowSpan; }
set { _rowSpan = value; }
}
private int _columnSpan = 1;
///
/// 結合する列数
///
///
///
///
[Category("セル結合")]
[Description("列数")]
public int ColumnSpan
{
get { return _columnSpan; }
set { _columnSpan = value; }
}
private System.Drawing.Color _backgroundColor = Color.Empty;
///
/// セルの背景色
///
///
///
///
[Category("表示")]
[Description("セルの背景色")]
public System.Drawing.Color BackgroundColor
{
get { return _backgroundColor; }
set { _backgroundColor = value; }
}
private System.Drawing.Color _foreColor = Color.Empty;
///
/// テキストの文字色
///
///
///
///
[Category("表示")]
[Description("テキストの文字色")]
public System.Drawing.Color ForeColor
{
get { return _foreColor; }
set { _foreColor = value; }
}
private string _text;
///
/// セルに関連付けられたテキスト
///
///
///
///
[Category("表示")]
[Description("セルに関連付けられたテキストです")]
public string Text
{
get { return _text; }
set { _text = value; }
}
private DataGridViewContentAlignment _textAlign;
///
/// 結合されたセル内でのテキストの位置
///
///
///
///
[Category("表示")]
[Description("結合されたセル内のテキストの位置を決定します")]
public DataGridViewContentAlignment TextAlign
{
get { return _textAlign; }
set { _textAlign = value; }
}
private DataGridViewTriState _wrapMode = DataGridViewTriState.NotSet;
///
/// セルに含まれるテキスト形式の内容が 1 行に収まらないほど長い場合に、次の行に折り返されるか、
/// 切り捨てられるかを示す値を取得または設定する
///
///
///
///
[Category("表示")]
[Description("セル内のテキストが一行に収まらない場合にテキストを折り返す")]
public DataGridViewTriState WrapMode
{
get { return _wrapMode; }
set { _wrapMode = value; }
}
private bool _sortVisible;
///
/// 結合されている列に並び替えがある場合に並び替えの方向を表示する
///
///
///
///
[Category("表示")]
[Description("結合されている列に並び替えがある場合に並び替えの方向を表示する")]
public bool SortVisible
{
get { return _sortVisible; }
set { _sortVisible = value; }
}
}
}
次にDataGridViewの継承クラスを作成します。
クラスに以下ののプロパティを追加。
次にOnPaintイベントにヘッダセルの描画処理とセルの結合の描画処理を記述します。
スクロール時、コントロールのサイズ変更時および列の幅が変更された時に直前の描画が
残るのを防ぐために描画領域の無効化をしています。
VB.NET
Imports System
Imports System.Windows.Forms
Imports System.ComponentModel
Imports System.Drawing
'Imports MyLibrary.HeaderCell
Public Class CustomHeaderDataGridView
Inherits System.Windows.Forms.DataGridView
Private _item As New MyCollection(Me)
''' <summary>
''' 列ヘッダに表示するCellを設定します
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
<Category("列ヘッダのカスタマイズ")> _
<Description("列ヘッダに表示するCellを設定します")>
Public ReadOnly Property HeaderCells() As MyCollection
Get
Return _item
End Get
End Property
Friend Sub OnCollectionChanged()
Me.Invalidate()
End Sub
''' <summary>
''' コレクションの設定
''' </summary>
''' <remarks></remarks>
Public Class MyCollection
Inherits System.Collections.ObjectModel.Collection(Of HeaderCell)
Private _parent As CustomHeaderDataGridView
Friend Sub New(ByVal parent As CustomHeaderDataGridView)
_parent = parent
End Sub
Protected Overrides Sub ClearItems()
MyBase.ClearItems()
_parent.OnCollectionChanged()
End Sub
Protected Overrides Sub InsertItem(ByVal index As Integer, ByVal item As HeaderCell)
MyBase.InsertItem(index, item)
_parent.OnCollectionChanged()
End Sub
Protected Overrides Sub RemoveItem(ByVal index As Integer)
MyBase.RemoveItem(index)
_parent.OnCollectionChanged()
End Sub
Protected Overrides Sub SetItem(ByVal index As Integer, ByVal item As HeaderCell)
MyBase.SetItem(index, item)
_parent.OnCollectionChanged()
End Sub
End Class
Private _columnHeaderRowCount As Integer = 1
''' <summary>
''' 列ヘッダーの行数を設定します
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<Category("列ヘッダのカスタマイズ")> _
<Description("列ヘッダに表示する行を設定します")>
Public Property ColumnHeaderRowCount As Integer
Get
Return _columnHeaderRowCount
End Get
Set(ByVal value As Integer)
_columnHeaderRowCount = value
If value = 0 Then
_columnHeaderRowCount = 1
End If
MyBase.ColumnHeadersHeight = value * ColumnHeaderRowHeight + 2
MyBase.Refresh()
End Set
End Property
Private _columnHeaderRowHeight As Integer = 17
''' <summary>
''' 列ヘッダに表示する行の高さ
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<Category("列ヘッダのカスタマイズ")> _
<Description("列ヘッダに表示する行の高さを設定します")>
Public Property ColumnHeaderRowHeight As Integer
Get
Return _columnHeaderRowHeight
End Get
Set(ByVal value As Integer)
_columnHeaderRowHeight = value
MyBase.ColumnHeadersHeight = value * ColumnHeaderRowCount + 2
MyBase.Refresh()
End Set
End Property
''' <summary>
''' 列ヘッダーの境界線の種類
''' </summary>
''' <remarks></remarks>
Public Enum HeaderCellBorderStyle
SingleLine = 0
DoubleLine = 1
End Enum
Private _columnHeaderBorderStyle As HeaderCellBorderStyle = HeaderCellBorderStyle.SingleLine
''' <summary>
''' 列ヘッダーの線種
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
<Category("列ヘッダのカスタマイズ")> _
<Description("列ヘッダに線種を設定します")>
Public Property ColumnHeaderBorderStyle As HeaderCellBorderStyle
Get
Return _columnHeaderBorderStyle
End Get
Set(ByVal value As HeaderCellBorderStyle)
_columnHeaderBorderStyle = value
MyBase.Refresh()
End Set
End Property
<System.Diagnostics.DebuggerNonUserCode()> _
Public Sub New()
MyBase.New()
'この呼び出しは、コンポーネント デザイナーで必要です。
InitializeComponent()
MyBase.DoubleBuffered = True
End Sub
'Component は、コンポーネント一覧に後処理を実行するために dispose をオーバーライドします。
<System.Diagnostics.DebuggerNonUserCode()> _
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
Finally
MyBase.Dispose(disposing)
End Try
End Sub
'コンポーネント デザイナーで必要です。
Private components As System.ComponentModel.IContainer
'メモ: 以下のプロシージャはコンポーネント デザイナーで必要です。
'コンポーネント デザイナーを使って変更できます。
'コード エディターを使って変更しないでください。
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
components = New System.ComponentModel.Container()
End Sub
''' <summary>
''' 再描画をするとき
''' </summary>
''' <param name="e"></param>
''' <remarks></remarks>
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)
Try
'---------------------------------------------------------------------------------------------------------
'ヘッダーセルの描画
'---------------------------------------------------------------------------------------------------------
'ヘッダーの行の高さの取得
Dim rowHeight As Integer = MyBase.ColumnHeadersHeight
If Me.ColumnHeaderRowCount > 0 Then
rowHeight = MyBase.ColumnHeadersHeight / Me.ColumnHeaderRowCount
End If
'線の太さ
Dim lineWidth As Integer = 1
For i = 0 To ColumnCount - 1
For j = 0 To Me.ColumnHeaderRowCount - 1
'グッリドの線
Dim gridPen As New Pen(MyBase.GridColor)
'背景色
Dim backBrash As New SolidBrush(MyBase.ColumnHeadersDefaultCellStyle.BackColor)
'くぼみ線
Dim whiteBrash As New SolidBrush(Color.White)
Try
'列ヘッダーの描画領域
Dim rect As Rectangle = MyBase.GetCellDisplayRectangle(i, -1, True)
'列ヘッダーの描画領域の底部の座標を保存
Dim btm As Integer = rect.Bottom
'セルの描画領域のY座標
Select Case MyBase.BorderStyle
Case Windows.Forms.BorderStyle.None
rect.Y = rowHeight * j
Case Windows.Forms.BorderStyle.FixedSingle
rect.Y = rowHeight * j + lineWidth
Case Windows.Forms.BorderStyle.Fixed3D
rect.Y = rowHeight * j + (lineWidth * 2)
End Select
'セルの描画領域のX座標
rect.X -= lineWidth
'セルの描画領域の高さ
rect.Height = rowHeight
'最下行の場合高さを調整
If j = Me.ColumnHeaderRowCount - 1 Then
rect.Height = btm - rect.Y - lineWidth
End If
'セルを囲む線の描画
e.Graphics.DrawRectangle(gridPen, rect)
'セルの背景色の領域
rect.Y += lineWidth
rect.X += lineWidth
rect.Height -= lineWidth
rect.Width -= lineWidth
'背景色の描画
If ColumnHeaderBorderStyle <> HeaderCellBorderStyle.DoubleLine Then
'Single線の場合
e.Graphics.FillRectangle(backBrash, rect)
Else
'くぼみ線の場合
'rect.Width -= lineWidth
e.Graphics.FillRectangle(whiteBrash, rect)
rect.Y += lineWidth
rect.X += lineWidth
rect.Height -= lineWidth
rect.Width -= lineWidth
e.Graphics.FillRectangle(backBrash, rect)
End If
'見出しを最下列に表示
If j = Me.ColumnHeaderRowCount - 1 Then
Dim text As String = MyBase.Columns(i).HeaderText
If MyBase.SortedColumn IsNot Nothing AndAlso MyBase.SortedColumn Is Me.Columns(i) Then
If MyBase.SortOrder = Windows.Forms.SortOrder.Ascending Then
text = text & " ▼"
ElseIf MyBase.SortOrder = Windows.Forms.SortOrder.Descending Then
text = text & " ▲"
End If
End If
Dim formatFlg As TextFormatFlags = GetTextFormatFlags(MyBase.ColumnHeadersDefaultCellStyle.Alignment, _
MyBase.ColumnHeadersDefaultCellStyle.WrapMode)
TextRenderer.DrawText(e.Graphics, text, MyBase.ColumnHeadersDefaultCellStyle.Font, _
rect, MyBase.ColumnHeadersDefaultCellStyle.ForeColor, _
formatFlg)
End If
Finally
'リソースの解放
gridPen.Dispose()
backBrash.Dispose()
whiteBrash.Dispose()
End Try
Next
Next
'---------------------------------------------------------------------------------------------------------
'ヘッダーのセル結合
'---------------------------------------------------------------------------------------------------------
'ヘッダーセル定義の処理
For i = 0 To Me.HeaderCells.Count - 1
'セルの結合の開始行がヘッダーの行数より大きい場合は除外
If HeaderCells(i).Row > Me.ColumnHeaderRowCount - 1 Then
Continue For
End If
'セルの結合の開始列の列インデックスが列数より大きい場合は除外
If HeaderCells(i).Column > MyBase.ColumnCount - 1 Then
Continue For
End If
'描画領域の設定
Dim rect As Rectangle = Nothing
'結合する列中のソート状態
Dim sortText As String = String.Empty
'結合するセルの各列の幅を取得し描画領域の幅を決める、ソートされている列の場合Textに表示するソート方向の設定
For j = Me.HeaderCells(i).Column To Me.HeaderCells(i).Column + Me.HeaderCells(i).ColumnSpan - 1
'列が画面に表示されていない場合は処理しない
If MyBase.Columns(j).Displayed = False Then
Continue For
End If
'列ヘッダーの領域の幅
If rect = Nothing Then
'結合するセルの開始列の場合
rect = MyBase.GetCellDisplayRectangle(j, -1, True)
Else
'結合するセルの2列目以降の場合
rect.Width += MyBase.GetCellDisplayRectangle(j, -1, True).Width
End If
'ソート列の場合
If HeaderCells(i).SortVisible = True AndAlso MyBase.SortedColumn IsNot Nothing AndAlso MyBase.SortedColumn Is MyBase.Columns(j) Then
If MyBase.SortOrder = Windows.Forms.SortOrder.Ascending Then
sortText = " ▼"
ElseIf MyBase.SortOrder = Windows.Forms.SortOrder.Descending Then
sortText = " ▲"
End If
End If
Next
'結合するセルが画面中に無い場合
If rect = Nothing Then
Continue For
End If
'結合する行がヘッダー行数より大きい場合
Dim rowSapn As Integer = Me.HeaderCells(i).RowSpan
If rowSapn > ColumnHeaderRowCount Then
rowSapn = ColumnHeaderRowCount
End If
'列ヘッダーの描画領域の底部の座標を保存
Dim btm As Integer = rect.Bottom
'結合するセルの描画領域のY座標
Select Case MyBase.BorderStyle
Case Windows.Forms.BorderStyle.None
rect.Y = rowHeight * (Me.HeaderCells(i).Row)
Case Windows.Forms.BorderStyle.FixedSingle
rect.Y = rowHeight * (Me.HeaderCells(i).Row) + lineWidth
Case Windows.Forms.BorderStyle.Fixed3D
rect.Y = rowHeight * (Me.HeaderCells(i).Row) + (lineWidth * 2)
End Select
'結合するセルの描画領域のX座標
rect.X -= lineWidth
'結合するセルの描画領域の高さ
rect.Height = rowHeight * rowSapn
'最下行の場合は描画領域の高さを調整する
If Me.HeaderCells(i).Row + rowSapn = Me.ColumnHeaderRowCount Then
rect.Height = btm - rect.Y - lineWidth
End If
'グッリドの線
Dim gridPen As New Pen(MyBase.GridColor)
'背景色の取得
Dim backgroundColor As System.Drawing.Color = MyBase.ColumnHeadersDefaultCellStyle.BackColor
'セルの背景色が設定されている場合
If Not Me.HeaderCells(i).BackgroundColor = Color.Empty Then
backgroundColor = Me.HeaderCells(i).BackgroundColor
End If
'背景色
Dim backBrash As New SolidBrush(backgroundColor)
'くぼみ線
Dim whiteBrash As New SolidBrush(Color.White)
Try
'枠線の描画
e.Graphics.DrawRectangle(gridPen, rect)
'結合セルの背景色の描画領域の設定
rect.Y += lineWidth
rect.X += lineWidth
rect.Height -= lineWidth
rect.Width -= lineWidth
'背景色の描画
If ColumnHeaderBorderStyle = HeaderCellBorderStyle.SingleLine Then
'Singleの場合
e.Graphics.FillRectangle(backBrash, rect)
Else
'くぼみ線の場合
e.Graphics.FillRectangle(whiteBrash, rect)
rect.Y += lineWidth
rect.X += lineWidth
rect.Height -= lineWidth
rect.Width -= lineWidth
e.Graphics.FillRectangle(backBrash, rect)
End If
'テキストの描画
Dim foreColor As System.Drawing.Color = MyBase.ColumnHeadersDefaultCellStyle.ForeColor
If Not Me.HeaderCells(i).ForeColor = Color.Empty Then
foreColor = Me.HeaderCells(i).ForeColor
End If
Dim formatFlg As TextFormatFlags = GetTextFormatFlags(Me.HeaderCells(i).TextAlign, Me.HeaderCells(i).WrapMode)
TextRenderer.DrawText(e.Graphics, Me.HeaderCells(i).Text & sortText, MyBase.ColumnHeadersDefaultCellStyle.Font, _
rect, foreColor, formatFlg)
Finally
'リソースの解放
gridPen.Dispose()
backBrash.Dispose()
whiteBrash.Dispose()
End Try
Next
Catch ex As Exception
MessageBox.Show(ex.ToString)
End Try
End Sub
''' <summary>
''' 指定のスタイルから描写するテキストのスタイルを取得する
''' </summary>
''' <param name="alignment">テキストのスタイル</param>
''' <param name="wrapMode">折り返</param>
''' <remarks>描写するテキストのスタイル</remarks>
Private Function GetTextFormatFlags(ByVal alignment As DataGridViewContentAlignment,
ByVal wrapMode As DataGridViewTriState) As TextFormatFlags
Try
''文字の描画
Dim formatFlg As TextFormatFlags = TextFormatFlags.Right Or TextFormatFlags.VerticalCenter Or TextFormatFlags.EndEllipsis
'表示位置
Select Case alignment
Case DataGridViewContentAlignment.BottomCenter
formatFlg = TextFormatFlags.Bottom Or TextFormatFlags.HorizontalCenter Or TextFormatFlags.EndEllipsis
Case DataGridViewContentAlignment.BottomLeft
formatFlg = TextFormatFlags.Bottom Or TextFormatFlags.Left Or TextFormatFlags.EndEllipsis
Case DataGridViewContentAlignment.BottomRight
formatFlg = TextFormatFlags.Bottom Or TextFormatFlags.Right Or TextFormatFlags.EndEllipsis
Case DataGridViewContentAlignment.MiddleCenter
formatFlg = TextFormatFlags.VerticalCenter Or TextFormatFlags.HorizontalCenter Or TextFormatFlags.EndEllipsis
Case DataGridViewContentAlignment.MiddleLeft
formatFlg = TextFormatFlags.VerticalCenter Or TextFormatFlags.Left Or TextFormatFlags.EndEllipsis
Case DataGridViewContentAlignment.MiddleRight
formatFlg = TextFormatFlags.VerticalCenter Or TextFormatFlags.Right Or TextFormatFlags.EndEllipsis
Case DataGridViewContentAlignment.TopCenter
formatFlg = TextFormatFlags.Top Or TextFormatFlags.HorizontalCenter Or TextFormatFlags.EndEllipsis
Case DataGridViewContentAlignment.TopLeft
formatFlg = TextFormatFlags.Top Or TextFormatFlags.Left Or TextFormatFlags.EndEllipsis
Case DataGridViewContentAlignment.TopRight
formatFlg = TextFormatFlags.Top Or TextFormatFlags.Right Or TextFormatFlags.EndEllipsis
End Select
'折り返し
Select Case wrapMode
Case DataGridViewTriState.False
Case DataGridViewTriState.NotSet
Case DataGridViewTriState.True
formatFlg = formatFlg Or TextFormatFlags.WordBreak
End Select
Return formatFlg
Catch ex As Exception
Throw
End Try
End Function
''' <summary>
''' セルを結合する対象の列の描画領域の無効化
''' </summary>
''' <remarks></remarks>
Private Sub InvalidateUnitColumns()
Try
Dim hRect As Rectangle = MyBase.DisplayRectangle
hRect.Height = MyBase.ColumnHeadersHeight + 1
MyBase.Invalidate(hRect)
Catch ex As Exception
MessageBox.Show(ex.ToString)
End Try
End Sub
''' <summary>
''' スクロールが実行されたとき
''' </summary>
''' <param name="e"></param>
''' <remarks></remarks>
Protected Overrides Sub OnScroll(ByVal e As System.Windows.Forms.ScrollEventArgs)
MyBase.OnScroll(e)
Try
InvalidateUnitColumns()
Catch ex As Exception
MessageBox.Show(ex.ToString)
End Try
End Sub
''' <summary>
''' サイズが変更されたとき
''' </summary>
''' <param name="e"></param>
''' <remarks></remarks>
Protected Overrides Sub OnSizeChanged(ByVal e As System.EventArgs)
MyBase.OnSizeChanged(e)
Try
InvalidateUnitColumns()
Catch ex As Exception
MessageBox.Show(ex.ToString)
End Try
End Sub
''' <summary>
''' 列の幅が変更されたとき
''' </summary>
''' <param name="e"></param>
''' <remarks></remarks>
Protected Overrides Sub OnColumnWidthChanged(ByVal e As System.Windows.Forms.DataGridViewColumnEventArgs)
MyBase.OnColumnWidthChanged(e)
Try
InvalidateUnitColumns()
Catch ex As Exception
MessageBox.Show(ex.ToString)
End Try
End Sub
''' <summary>
''' 行の境界線がダブルクリックされた時
''' </summary>
''' <param name="e"></param>
''' <remarks></remarks>
Protected Overrides Sub OnRowDividerDoubleClick(ByVal e As System.Windows.Forms.DataGridViewRowDividerDoubleClickEventArgs)
MyBase.OnRowDividerDoubleClick(e)
Try
'行ヘッダーの境界線がダブルクリックされたへっだーの高さを整える
If e.RowIndex = -1 Then
MyBase.ColumnHeadersHeight = Me.ColumnHeaderRowCount * Me.ColumnHeaderRowHeight + 2
End If
Catch ex As Exception
MessageBox.Show(ex.ToString)
End Try
End Sub
''' <summary>
''' マウスのボタンが押された時
''' </summary>
''' <param name="e"></param>
''' <remarks></remarks>
Protected Overrides Sub OnMouseDown(e As System.Windows.Forms.MouseEventArgs)
MyBase.OnMouseDown(e)
Try
'列幅、行高を調整するドラグ線を見えるようにするためにダブルバッファを解除する
MyBase.DoubleBuffered = False
Catch ex As Exception
MessageBox.Show(ex.ToString)
End Try
End Sub
''' <summary>
''' マウスのボタンが離された時
''' </summary>
''' <param name="e"></param>
''' <remarks></remarks>
Protected Overrides Sub OnMouseUp(e As System.Windows.Forms.MouseEventArgs)
MyBase.OnMouseUp(e)
Try
'OnMouseDownイベントで解除されたダブルバッファを適用する
MyBase.DoubleBuffered = True
Catch ex As Exception
MessageBox.Show(ex.ToString)
End Try
End Sub
End Class
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
using System.Data;
using System.Diagnostics;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;
namespace ClassLibrary1
{
class CustomHeaderDataGridView : System.Windows.Forms.DataGridView
{
private MyCollection _item = null;
///
/// 列ヘッダに表示するCellを設定します
///
///
///
///
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[Category("列ヘッダのカスタマイズ")]
[Description("列ヘッダに表示するCellを設定します")]
public MyCollection HeaderCells
{
get { return _item; }
}
internal void OnCollectionChanged()
{
this.Invalidate();
}
///
/// コレクションの設定
///
///
public class MyCollection : System.Collections.ObjectModel.Collection<HeaderCell>
{
private CustomHeaderDataGridView _parent;
internal MyCollection(CustomHeaderDataGridView parent)
{
_parent = parent;
}
protected override void ClearItems()
{
base.ClearItems();
_parent.OnCollectionChanged();
}
protected override void InsertItem(int index, HeaderCell item)
{
base.InsertItem(index, item);
_parent.OnCollectionChanged();
}
protected override void RemoveItem(int index)
{
base.RemoveItem(index);
_parent.OnCollectionChanged();
}
protected override void SetItem(int index, HeaderCell item)
{
base.SetItem(index, item);
_parent.OnCollectionChanged();
}
}
private int _columnHeaderRowCount = 1;
///
/// 列ヘッダーの行数を設定します
///
///
///
///
[Category("列ヘッダのカスタマイズ")]
[Description("列ヘッダに表示する行を設定します")]
public int ColumnHeaderRowCount
{
get { return _columnHeaderRowCount; }
set
{
_columnHeaderRowCount = value;
if (value == 0)
{
_columnHeaderRowCount = 1;
}
base.ColumnHeadersHeight = value * ColumnHeaderRowHeight + 2;
base.Refresh();
}
}
private int _columnHeaderRowHeight = 17;
//
/// 列ヘッダに表示する行の高さ
///
///
///
///
[Category("列ヘッダのカスタマイズ")]
[Description("列ヘッダに表示する行の高さを設定します")]
public int ColumnHeaderRowHeight
{
get { return _columnHeaderRowHeight; }
set
{
_columnHeaderRowHeight = value;
base.ColumnHeadersHeight = value * ColumnHeaderRowCount + 2;
base.Refresh();
}
}
///
/// 列ヘッダーの境界線の種類
///
///
public enum HeaderCellBorderStyle
{
SingleLine = 0,
DoubleLine = 1
}
private HeaderCellBorderStyle _columnHeaderBorderStyle = HeaderCellBorderStyle.SingleLine;
///
/// 列ヘッダーの線種
///
///
///
///
[Category("列ヘッダのカスタマイズ")]
[Description("列ヘッダに線種を設定します")]
public HeaderCellBorderStyle ColumnHeaderBorderStyle
{
get { return _columnHeaderBorderStyle; }
set
{
_columnHeaderBorderStyle = value;
base.Refresh();
}
}
[System.Diagnostics.DebuggerNonUserCode()]
public CustomHeaderDataGridView()
: base()
{
//この呼び出しは、コンポーネント デザイナーで必要です。
InitializeComponent();
this._item = new MyCollection(this);
base.DoubleBuffered = true;
}
//Component は、コンポーネント一覧に後処理を実行するために dispose をオーバーライドします。
[System.Diagnostics.DebuggerNonUserCode()]
protected override void Dispose(bool disposing)
{
try
{
if (disposing && components != null)
{
components.Dispose();
}
}
finally
{
base.Dispose(disposing);
}
}
//コンポーネント デザイナーで必要です。
private System.ComponentModel.IContainer components;
//メモ: 以下のプロシージャはコンポーネント デザイナーで必要です。
//コンポーネント デザイナーを使って変更できます。
//コード エディターを使って変更しないでください。
[System.Diagnostics.DebuggerStepThrough()]
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
/// 再描画をするとき
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
base.OnPaint(e);
try
{
//---------------------------------------------------------------------------------------------------------
//ヘッダーセルの描画
//---------------------------------------------------------------------------------------------------------
//ヘッダーの行の高さの取得
int rowHeight = base.ColumnHeadersHeight;
if (this.ColumnHeaderRowCount > 0)
{
rowHeight = base.ColumnHeadersHeight / this.ColumnHeaderRowCount;
}
//線の太さ
int lineWidth = 1;
for (int i = 0; i <= ColumnCount - 1; i++)
{
for (int j = 0; j <= this.ColumnHeaderRowCount - 1; j++)
{
//グッリドの線
Pen gridPen = new Pen(base.GridColor);
//背景色
SolidBrush backBrash = new SolidBrush(base.ColumnHeadersDefaultCellStyle.BackColor);
//くぼみ線
SolidBrush whiteBrash = new SolidBrush(Color.White);
try
{
//列ヘッダーの描画領域
Rectangle rect = base.GetCellDisplayRectangle(i, -1, true);
//列ヘッダーの描画領域の底部の座標を保存
int btm = rect.Bottom;
//セルの描画領域のY座標
switch (base.BorderStyle)
{
case BorderStyle.None:
rect.Y = rowHeight * j;
break;
case BorderStyle.FixedSingle:
rect.Y = rowHeight * j + lineWidth;
break;
case BorderStyle.Fixed3D:
rect.Y = rowHeight * j + (lineWidth * 2);
break;
}
//セルの描画領域のX座標
rect.X -= lineWidth;
//セルの描画領域の高さ
rect.Height = rowHeight;
//最下行の場合高さを調整
if (j == this.ColumnHeaderRowCount - 1)
{
rect.Height = btm - rect.Y - lineWidth;
}
//セルを囲む線の描画
e.Graphics.DrawRectangle(gridPen, rect);
//セルの背景色の領域
rect.Y += lineWidth;
rect.X += lineWidth;
rect.Height -= lineWidth;
rect.Width -= lineWidth;
//背景色の描画
if (ColumnHeaderBorderStyle != HeaderCellBorderStyle.DoubleLine)
{
//Single線の場合
e.Graphics.FillRectangle(backBrash, rect);
}
else
{
//くぼみ線の場合
//rect.Width -= lineWidth
e.Graphics.FillRectangle(whiteBrash, rect);
rect.Y += lineWidth;
rect.X += lineWidth;
rect.Height -= lineWidth;
rect.Width -= lineWidth;
e.Graphics.FillRectangle(backBrash, rect);
}
//見出しを最下列に表示
if (j == this.ColumnHeaderRowCount - 1)
{
string text = base.Columns[i].HeaderText;
if (base.SortedColumn != null && object.ReferenceEquals(base.SortedColumn, this.Columns[i]))
{
if (base.SortOrder == SortOrder.Ascending)
{
text = text + " ▼";
}
else if (base.SortOrder == SortOrder.Descending)
{
text = text + " ▲";
}
}
TextFormatFlags formatFlg = GetTextFormatFlags(base.ColumnHeadersDefaultCellStyle.Alignment, base.ColumnHeadersDefaultCellStyle.WrapMode);
TextRenderer.DrawText(e.Graphics, text, base.ColumnHeadersDefaultCellStyle.Font, rect, base.ColumnHeadersDefaultCellStyle.ForeColor, formatFlg);
}
}
finally
{
//リソースの解放
gridPen.Dispose();
backBrash.Dispose();
whiteBrash.Dispose();
}
}
}
//---------------------------------------------------------------------------------------------------------
//ヘッダーのセル結合
//---------------------------------------------------------------------------------------------------------
//ヘッダーセル定義の処理
for (int i = 0; i <= this.HeaderCells.Count - 1; i++)
{
//セルの結合の開始行がヘッダーの行数より大きい場合は除外
if (HeaderCells[i].Row > this.ColumnHeaderRowCount - 1)
{
continue;
}
//セルの結合の開始列の列インデックスが列数より大きい場合は除外
if (HeaderCells[i].Column > base.ColumnCount - 1)
{
continue;
}
//描画領域の設定
Rectangle rect = Rectangle.Empty;
//結合する列中のソート状態
string sortText = string.Empty;
//結合するセルの各列の幅を取得し描画領域の幅を決める、ソートされている列の場合Textに表示するソート方向の設定
for (int j = this.HeaderCells[i].Column; j <= this.HeaderCells[i].Column + this.HeaderCells[i].ColumnSpan - 1; j++)
{
//列が画面に表示されていない場合は処理しない
if (base.Columns[j].Displayed == false)
{
continue;
}
//列ヘッダーの領域の幅
if (rect.IsEmpty)
{
//結合するセルの開始列の場合
rect = base.GetCellDisplayRectangle(j, -1, true);
}
else
{
//結合するセルの2列目以降の場合
rect.Width += base.GetCellDisplayRectangle(j, -1, true).Width;
}
//ソート列の場合
if (HeaderCells[i].SortVisible == true && base.SortedColumn != null && object.ReferenceEquals(base.SortedColumn, base.Columns[j]))
{
if (base.SortOrder == SortOrder.Ascending)
{
sortText = " ▼";
}
else if (base.SortOrder == SortOrder.Descending)
{
sortText = " ▲";
}
}
}
//結合するセルが画面中に無い場合
if (rect == null)
{
continue;
}
//結合する行がヘッダー行数より大きい場合
int rowSapn = this.HeaderCells[i].RowSpan;
if (rowSapn > ColumnHeaderRowCount)
{
rowSapn = ColumnHeaderRowCount;
}
//列ヘッダーの描画領域の底部の座標を保存
int btm = rect.Bottom;
//結合するセルの描画領域のY座標
switch (base.BorderStyle)
{
case BorderStyle.None:
rect.Y = rowHeight * (this.HeaderCells[i].Row);
break;
case BorderStyle.FixedSingle:
rect.Y = rowHeight * (this.HeaderCells[i].Row) + lineWidth;
break;
case BorderStyle.Fixed3D:
rect.Y = rowHeight * (this.HeaderCells[i].Row) + (lineWidth * 2);
break;
}
//結合するセルの描画領域のX座標
rect.X -= lineWidth;
//結合するセルの描画領域の高さ
rect.Height = rowHeight * rowSapn;
//最下行の場合は描画領域の高さを調整する
if (this.HeaderCells[i].Row + rowSapn == this.ColumnHeaderRowCount)
{
rect.Height = btm - rect.Y - lineWidth;
}
//グッリドの線
Pen gridPen = new Pen(base.GridColor);
//背景色の取得
System.Drawing.Color backgroundColor = base.ColumnHeadersDefaultCellStyle.BackColor;
//セルの背景色が設定されている場合
if (!(this.HeaderCells[i].BackgroundColor == Color.Empty))
{
backgroundColor = this.HeaderCells[i].BackgroundColor;
}
//背景色
SolidBrush backBrash = new SolidBrush(backgroundColor);
//くぼみ線
SolidBrush whiteBrash = new SolidBrush(Color.White);
try
{
//枠線の描画
e.Graphics.DrawRectangle(gridPen, rect);
//結合セルの背景色の描画領域の設定
rect.Y += lineWidth;
rect.X += lineWidth;
rect.Height -= lineWidth;
rect.Width -= lineWidth;
//背景色の描画
if (ColumnHeaderBorderStyle == HeaderCellBorderStyle.SingleLine)
{
//Singleの場合
e.Graphics.FillRectangle(backBrash, rect);
}
else
{
//くぼみ線の場合
e.Graphics.FillRectangle(whiteBrash, rect);
rect.Y += lineWidth;
rect.X += lineWidth;
rect.Height -= lineWidth;
rect.Width -= lineWidth;
e.Graphics.FillRectangle(backBrash, rect);
}
//テキストの描画
System.Drawing.Color foreColor = base.ColumnHeadersDefaultCellStyle.ForeColor;
if (!(this.HeaderCells[i].ForeColor == Color.Empty))
{
foreColor = this.HeaderCells[i].ForeColor;
}
TextFormatFlags formatFlg = GetTextFormatFlags(this.HeaderCells[i].TextAlign, this.HeaderCells[i].WrapMode);
TextRenderer.DrawText(e.Graphics, this.HeaderCells[i].Text + sortText, base.ColumnHeadersDefaultCellStyle.Font, rect, foreColor, formatFlg);
}
finally
{
//リソースの解放
gridPen.Dispose();
backBrash.Dispose();
whiteBrash.Dispose();
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
/// <summary>
/// 指定のスタイルから描写するテキストのスタイルを取得する
/// </summary>
/// <param name="alignment">テキストのスタイル</param>
/// <param name="wrapMode">折り返</param>
/// <remarks>描写するテキストのスタイル</remarks>
private TextFormatFlags GetTextFormatFlags(DataGridViewContentAlignment alignment, DataGridViewTriState wrapMode)
{
try
{
//'文字の描画
TextFormatFlags formatFlg = TextFormatFlags.Right | TextFormatFlags.VerticalCenter | TextFormatFlags.EndEllipsis;
//表示位置
switch (alignment)
{
case DataGridViewContentAlignment.BottomCenter:
formatFlg = TextFormatFlags.Bottom | TextFormatFlags.HorizontalCenter | TextFormatFlags.EndEllipsis;
break;
case DataGridViewContentAlignment.BottomLeft:
formatFlg = TextFormatFlags.Bottom | TextFormatFlags.Left | TextFormatFlags.EndEllipsis;
break;
case DataGridViewContentAlignment.BottomRight:
formatFlg = TextFormatFlags.Bottom | TextFormatFlags.Right | TextFormatFlags.EndEllipsis;
break;
case DataGridViewContentAlignment.MiddleCenter:
formatFlg = TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter | TextFormatFlags.EndEllipsis;
break;
case DataGridViewContentAlignment.MiddleLeft:
formatFlg = TextFormatFlags.VerticalCenter | TextFormatFlags.Left | TextFormatFlags.EndEllipsis;
break;
case DataGridViewContentAlignment.MiddleRight:
formatFlg = TextFormatFlags.VerticalCenter | TextFormatFlags.Right | TextFormatFlags.EndEllipsis;
break;
case DataGridViewContentAlignment.TopCenter:
formatFlg = TextFormatFlags.Top | TextFormatFlags.HorizontalCenter | TextFormatFlags.EndEllipsis;
break;
case DataGridViewContentAlignment.TopLeft:
formatFlg = TextFormatFlags.Top | TextFormatFlags.Left | TextFormatFlags.EndEllipsis;
break;
case DataGridViewContentAlignment.TopRight:
formatFlg = TextFormatFlags.Top | TextFormatFlags.Right | TextFormatFlags.EndEllipsis;
break;
}
//折り返し
switch (wrapMode)
{
case DataGridViewTriState.False:
break;
case DataGridViewTriState.NotSet:
break;
case DataGridViewTriState.True:
formatFlg = formatFlg | TextFormatFlags.WordBreak;
break;
}
return formatFlg;
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// セルを結合する対象の列の描画領域の無効化
/// </summary>
/// <remarks></remarks>
private void InvalidateUnitColumns()
{
try
{
Rectangle hRect = base.DisplayRectangle;
hRect.Height = base.ColumnHeadersHeight + 1;
base.Invalidate(hRect);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
/// <summary>
/// スクロールが実行されたとき
/// </summary>
/// <param name="e"></param>
/// <remarks></remarks>
protected override void OnScroll(System.Windows.Forms.ScrollEventArgs e)
{
base.OnScroll(e);
try
{
InvalidateUnitColumns();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
/// <summary>
/// サイズが変更されたとき
/// </summary>
/// <param name="e"></param>
/// <remarks></remarks>
protected override void OnSizeChanged(System.EventArgs e)
{
base.OnSizeChanged(e);
try
{
InvalidateUnitColumns();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
/// <summary>
/// 列の幅が変更されたとき
/// </summary>
/// <param name="e"></param>
/// <remarks></remarks>
protected override void OnColumnWidthChanged(System.Windows.Forms.DataGridViewColumnEventArgs e)
{
base.OnColumnWidthChanged(e);
try
{
InvalidateUnitColumns();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
/// <summary>
/// 行の境界線がダブルクリックされた時
/// </summary>
/// <param name="e"></param>
/// <remarks></remarks>
protected override void OnRowDividerDoubleClick(System.Windows.Forms.DataGridViewRowDividerDoubleClickEventArgs e)
{
base.OnRowDividerDoubleClick(e);
try
{
//行ヘッダーの境界線がダブルクリックされたへっだーの高さを整える
if (e.RowIndex == -1)
{
base.ColumnHeadersHeight = this.ColumnHeaderRowCount * this.ColumnHeaderRowHeight + 2;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
/// <summary>
/// マウスのボタンが押された時
/// </summary>
/// <param name="e"></param>
/// <remarks></remarks>
protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
{
base.OnMouseDown(e);
try
{
//列幅、行高を調整するドラグ線を見えるようにするためにダブルバッファを解除する
base.DoubleBuffered = false;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
/// <summary>
/// マウスのボタンが離された時
/// </summary>
/// <param name="e"></param>
/// <remarks></remarks>
protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e)
{
base.OnMouseUp(e);
try
{
//OnMouseDownイベントで解除されたダブルバッファを適用する
base.DoubleBuffered = true;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
}
Hi, i have a question mind can send me the project file for me to Download? i really like to have the columns group header i try the code but i keep getting error can paste the download link here so anyone need this can download.
返信削除Thank you.