先ずは列ヘッダーのセルの結合のための定義をコレクションエディターで表示するために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.