编程过程中经常遇到数据合并和多行标头的情况,以前用VB6挺顺手,现在用.net后,感觉一切都变了,查阅了很多人的资料后,我也简单的编写了一个,现在发出来,但愿有缘人能够将它完善,或者有所借鉴,我就足矣。因为本人技术有限,不当之处请多包涵。
使用的是中文版本的VS2005
'类的代码
Imports System.ComponentModel
Imports System.Collections.Generic
Public Class DGV_MulCapRowMerge
Inherits DataGridView
Private _columnCaptions As String()
Private _ColCap As String(,)
Private _cellHeight As Integer = 25
Private _columnDeep As Integer = 1
Private _HeaderFont As Font = Me.Font
Private _mergecolumnname As List(Of String) = New List(Of String)()
<Description("设置或获得数据列合并的集合")> _
Public Property MergeColumnNames() As List(Of String)
Get
Return _mergecolumnname
End Get
Set(ByVal Value As List(Of String))
_mergecolumnname = Value
End Set
End Property
<Description("设置或获得标头的字体")> _
Public Property ColHeaderFont() As Font
Get
Return _HeaderFont
End Get
Set(ByVal value As Font)
_HeaderFont = value
End Set
End Property
<Description("设置或获得合并表头的深度")> _
Public Property ColumnDeep() As Integer
Get
If Me.Columns.Count = 0 Then
_columnDeep = 1
End If
Me.ColumnHeadersHeight = _cellHeight * _columnDeep
Return _columnDeep
End Get
Set(ByVal value As Integer)
If value < 1 Then
_columnDeep = 1
Else
_columnDeep = value
End If
Me.ColumnHeadersHeight = _cellHeight * _columnDeep
End Set
End Property
<Description("添加合并式单元格绘制的所需要的对象")> _
Public Property ColumnSCaption() As String()
Get
Return _columnCaptions
End Get
Set(ByVal value As String())
_columnCaptions = value
GetCaption()
End Set
End Property
Private Sub GetCaption()
Dim iRow As Integer = _columnCaptions.GetLength(0)
If iRow > 0 Then '表示设置OK
On Error Resume Next
Dim strCap As String() = _columnCaptions(0).Split(",")
Dim iCol As Integer = strCap.GetLength(0) - 1
' Me.Columns.Clear()
ReDim Preserve _ColCap(iRow,iCol)
For iR As Integer = 0 To iRow - 1
For iC As Integer = 0 To iCol
_ColCap(iR,iC) = strCap(iC)
Next
If iR + 1 < iRow Then
strCap = _columnCaptions(iR + 1).Split(",")
End If
Next
End If
End Sub
Protected Overrides Sub OnCellPainting(ByVal e As DataGridViewCellPaintingEventArgs)
If e.RowIndex > -1 And e.ColumnIndex > -1 Then '数据区重新回执
DrawCell(e)
ElseIf e.RowIndex = -1 And e.ColumnIndex > -1 Then '列头重新绘制
If _columnDeep = 1 Then
MyBase.OnCellPainting(e)
' e.Handled = True
Exit Sub
End If
Dim ILev As Integer = ColumnDeep
Do While ILev > 0
PaintUnitHeader(e,ILev)
ILev = ILev - 1
Loop
e.Handled = True
ElseIf e.ColumnIndex = -1 Then
MyBase.OnCellPainting(e)
Exit Sub
End If
End Sub
Private Sub DrawCell(ByVal e As DataGridViewCellPaintingEventArgs)
If e.CellStyle.Alignment = DataGridViewContentAlignment.NotSet Then
e.CellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
End If
Dim gridBrush As Brush = New SolidBrush(Me.GridColor)
Dim backBrush As SolidBrush = New SolidBrush(Color.White)
Dim fontBrush As SolidBrush = New SolidBrush(e.CellStyle.ForeColor)
Dim cellwidth As Integer
Dim UpRows As Integer = 0
Dim DownRows As Integer = 0
Dim count As Integer = 0
Try
If Me.MergeColumnNames.Contains(Me.Columns(e.ColumnIndex).Name) And e.RowIndex <> -1 Then '如果本列需要合并
cellwidth = e.CellBounds.Width
Dim gridLinePen As Pen = New Pen(gridBrush)
Dim curValue As String = CType(e.Value,String)
If curValue Is Nothing Then Exit Sub
Dim curSelected As String = CType(Me.CurrentRow.Cells(e.ColumnIndex).Value,String)
If curSelected Is Nothing Then Exit Sub
For i As Integer = e.RowIndex To Me.Rows.Count - 1 Step 1
If Me.Rows(i).Cells(e.ColumnIndex).Value.ToString().Equals(curValue) Then
If e.ColumnIndex > 0 Then
If Me.MergeColumnNames.Contains(Me.Columns(e.ColumnIndex - 1).Name) And i >= 1 Then '如果前一列合并
If Not Me.Rows(i).Cells(e.ColumnIndex - 1).Value.ToString().Equals(Me.Rows(i - 1).Cells(e.ColumnIndex - 1).Value.ToString()) Then Exit For
End If
End If
DownRows = DownRows + 1
Else
Exit For
End If
Next
For j As Integer = e.RowIndex To 0 Step -1
If Me.Rows(j).Cells(e.ColumnIndex).Value.ToString().Equals(curValue) Then
If e.ColumnIndex > 0 Then
If Me.MergeColumnNames.Contains(Me.Columns(e.ColumnIndex - 1).Name) And j < e.RowIndex Then '如果前一列合并
If Not Me.Rows(j).Cells(e.ColumnIndex - 1).Value.ToString().Equals(Me.Rows(j + 1).Cells(e.ColumnIndex - 1).Value.ToString()) Then Exit For
End If
End If
UpRows = UpRows + 1
Else
Exit For
End If
Next
count = DownRows + UpRows - 1
If count < 2 Then Return
If Me.Rows(e.RowIndex).Selected Then
backBrush.Color = e.CellStyle.SelectionBackColor
fontBrush.Color = e.CellStyle.SelectionForeColor
End If
'填充清空
e.Graphics.FillRectangle(backBrush,e.CellBounds.X,e.CellBounds.Y - e.CellBounds.Height * (UpRows - 1),cellwidth,e.CellBounds.Height * count)
'底线
e.Graphics.DrawLine(gridLinePen,e.CellBounds.Left,e.CellBounds.Bottom + (DownRows - 1) * e.CellBounds.Height - 1,e.CellBounds.Right - 1,e.CellBounds.Bottom + (DownRows - 1) * e.CellBounds.Height - 1)
'右线
e.Graphics.DrawLine(gridLinePen,e.CellBounds.Top - e.CellBounds.Height * (UpRows - 1),e.CellBounds.Bottom + e.CellBounds.Height * (DownRows - 1))
'写内容
Dim fontheight As Integer = CType(e.Graphics.MeasureString(e.Value.ToString(),e.CellStyle.Font).Height,Integer)
Dim fontwidth As Integer = CType(e.Graphics.MeasureString(e.Value.ToString(),e.CellStyle.Font).Width,Integer)
Dim cellheight As Integer = e.CellBounds.Height
Select Case e.CellStyle.Alignment
Case DataGridViewContentAlignment.BottomCenter
e.Graphics.DrawString(CType(e.Value,String),e.CellStyle.Font,fontBrush,CType(e.CellBounds.X + (cellwidth - fontwidth) / 2,Single),e.CellBounds.Y + cellheight * DownRows - fontheight)
Case DataGridViewContentAlignment.BottomLeft
e.Graphics.DrawString(CType(e.Value,e.CellBounds.Y + cellheight * DownRows - fontheight)
Case DataGridViewContentAlignment.BottomRight
e.Graphics.DrawString(CType(e.Value,e.CellBounds.X + cellwidth - fontwidth,e.CellBounds.Y + cellheight * DownRows - fontheight)
Case DataGridViewContentAlignment.MiddleCenter
e.Graphics.DrawString(CType(e.Value,CType(e.CellBounds.Y + cellheight * (DownRows - UpRows) + (cellheight * count - fontheight) / 2,Single))
Case DataGridViewContentAlignment.MiddleLeft
e.Graphics.DrawString(CType(e.Value,CType(e.CellBounds.Y - cellheight * (UpRows - 1) + (cellheight * count - fontheight) / 2,Single))
Case DataGridViewContentAlignment.MiddleRight
e.Graphics.DrawString(CType(e.Value,Single))
Case DataGridViewContentAlignment.TopCenter
e.Graphics.DrawString(CType(e.Value,e.CellBounds.X + CType((cellwidth - fontwidth) / 2,e.CellBounds.Y - cellheight * (UpRows - 1))
Case DataGridViewContentAlignment.TopLeft
e.Graphics.DrawString(CType(e.Value,e.CellBounds.Y - cellheight * (UpRows - 1))
Case DataGridViewContentAlignment.TopRight
e.Graphics.DrawString(CType(e.Value,e.CellBounds.Y - cellheight * (UpRows - 1))
Case Else
e.Graphics.DrawString(CType(e.Value,Single))
End Select
e.Handled = True
End If
Catch
End Try
End Sub
'----------------------------------------------------------------------------------------------
' 绘制合并表头
'
'e 绘图参数集
'level 结点深度
'---------------------------------------------------------------------------------------------
Private Sub PaintUnitHeader( _
ByVal e As System.Windows.Forms.DataGridViewCellPaintingEventArgs,_
ByVal level As Integer,Optional ByVal IsDeep As Boolean = True)
Dim iCol As Integer = e.ColumnIndex
If level = 0 And iCol < 0 Then
Return
End If
'处理
Me.ColumnHeadersHeight = _cellHeight * _columnDeep
Dim uhRectangle As Rectangle
Dim uhWidth As Integer
Dim gridBrush As New SolidBrush(Me.GridColor)
Dim backColorBrush As New SolidBrush(e.CellStyle.BackColor)
Dim gridLinePen As New Pen(gridBrush)
Dim textFormat As New StringFormat()
Dim iDeepH As Integer
textFormat.Alignment = StringAlignment.Center
uhWidth = GetUnitHeaderWidth(iCol,level)
If uhWidth <= 0 Then Exit Sub
iDeepH = IsSingleChildNode(iCol,level)
If iDeepH < 0 Then Exit Sub
uhRectangle = New Rectangle( _
e.CellBounds.Left,_
e.CellBounds.Top + (level - 1 - iDeepH) * _cellHeight,_
uhWidth - 1,_
_cellHeight * (iDeepH + 1) - 1)
If e.ColumnIndex = -1 Then
uhRectangle = Me.GetCellDisplayRectangle(-1,-1,True)
End If
With e.Graphics
' On Error Resume Next
.FillRectangle(backColorBrush,uhRectangle)
'划底线
.DrawLine(gridLinePen _
,uhRectangle.Left _
,uhRectangle.Bottom _
,uhRectangle.Right _
,uhRectangle.Bottom)
'划右端线
.DrawLine(gridLinePen _
,uhRectangle.Top _
,uhRectangle.Bottom)
If e.ColumnIndex > -1 Then .DrawString(_ColCap(_columnDeep - level,iCol) _
,_HeaderFont _
,Brushes.Black _
,uhRectangle.Left + _
uhRectangle.Width / 2 - _
.MeasureString(_ColCap(_columnDeep - level,iCol),_HeaderFont).Width / 2 - 1 _
,uhRectangle.Top + _
uhRectangle.Height / 2 - _
.MeasureString(_ColCap(_columnDeep - level,_HeaderFont).Height / 2)
End With
End Sub
'------------------------------------------------------
'返回上下的跨度,0表示无跨度
'-----------------------------------------------------
Private Function IsSingleChildNode(ByVal ColIndex As Integer,ByVal Deep As Integer) As Integer
Dim strTemp As String = _ColCap(_columnDeep - Deep,ColIndex)
Dim IRc As Integer = 0
If Deep < _columnDeep Then
If strTemp = _ColCap(_columnDeep - Deep - 1,ColIndex) Then Return -1
End If
For iD As Integer = _columnDeep - Deep + 1 To _columnDeep - 1
If strTemp <> _ColCap(iD,ColIndex) Then Exit For
IRc += 1
Next
Return IRc
End Function
' 获得合并标题字段的宽度
'字段宽度
Private Function GetUnitHeaderWidth(ByVal ColIndex As Integer,ByVal Deep As Integer) As Integer
'获得字段的宽度
Dim uhWidth As Integer = 0
If ColIndex < 0 Then Return -1
If Deep = _columnDeep Then '最底层
Return Me.Columns(ColIndex).Width
Else
If ColIndex = 0 Then
Dim strTemp As String = _ColCap(_columnDeep - Deep,0)
For iC As Integer = 0 To Me.Columns.Count - 1
uhWidth += Me.Columns(iC).Width
If iC + 1 < Me.Columns.Count Then
If strTemp <> _ColCap(_columnDeep - Deep,iC + 1) Then Exit For
End If
Next
ElseIf ColIndex + 1 = Me.Columns.Count Then
Return Me.Columns(ColIndex).Width
Else
Dim strTemp As String = _ColCap(_columnDeep - Deep,ColIndex)
If strTemp = _ColCap(_columnDeep - Deep,ColIndex - 1) Then
Return -1 '因为和前面一致,不再重画
Else
For iC As Integer = ColIndex To Me.Columns.Count - 1
uhWidth += Me.Columns(iC).Width
If iC + 1 < Me.Columns.Count Then
If strTemp <> _ColCap(_columnDeep - Deep,iC + 1) Then Exit For
End If
Next
End If
End If
Return uhWidth
End If
End Function
End Class
'------
'窗体设计器自动产生的部分
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class Form2
Inherits System.Windows.Forms.Form
'Form 重写 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
'Windows 窗体设计器所必需的
Private components As System.ComponentModel.IContainer
'注意: 以下过程是 Windows 窗体设计器所必需的
'可以使用 Windows 窗体设计器修改它。
'不要使用代码编辑器修改它。
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(Form2))
Me.DgV_MulCapRowMerge1 = New MulCapRowMergeDGV.DGV_MulCapRowMerge
Me.Column1 = New System.Windows.Forms.DataGridViewTextBoxColumn
Me.Column2 = New System.Windows.Forms.DataGridViewTextBoxColumn
Me.Column3 = New System.Windows.Forms.DataGridViewTextBoxColumn
Me.Column4 = New System.Windows.Forms.DataGridViewTextBoxColumn
Me.Column5 = New System.Windows.Forms.DataGridViewTextBoxColumn
Me.Column6 = New System.Windows.Forms.DataGridViewTextBoxColumn
Me.Column7 = New System.Windows.Forms.DataGridViewTextBoxColumn
Me.Column8 = New System.Windows.Forms.DataGridViewTextBoxColumn
Me.Column9 = New System.Windows.Forms.DataGridViewTextBoxColumn
Me.Column10 = New System.Windows.Forms.DataGridViewTextBoxColumn
CType(Me.DgV_MulCapRowMerge1,System.ComponentModel.ISupportInitialize).BeginInit()
Me.SuspendLayout()
'
'DgV_MulCapRowMerge1
'
Me.DgV_MulCapRowMerge1.AllowUserToAddRows = False
Me.DgV_MulCapRowMerge1.ColHeaderFont = New System.Drawing.Font("宋体",9.0!,System.Drawing.FontStyle.Regular,System.Drawing.GraphicsUnit.Point,CType(134,Byte))
Me.DgV_MulCapRowMerge1.ColumnDeep = 1
Me.DgV_MulCapRowMerge1.ColumnHeadersHeight = 25
Me.DgV_MulCapRowMerge1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.DisableResizing
Me.DgV_MulCapRowMerge1.Columns.AddRange(New System.Windows.Forms.DataGridViewColumn() {Me.Column1,Me.Column2,Me.Column3,Me.Column4,Me.Column5,Me.Column6,Me.Column7,Me.Column8,Me.Column9,Me.Column10})
Me.DgV_MulCapRowMerge1.ColumnSCaption = New String() {"col1,col2,col3,col4,col5,col6,col7,col8","",""}
Me.DgV_MulCapRowMerge1.Dock = System.Windows.Forms.DockStyle.Fill
Me.DgV_MulCapRowMerge1.Location = New System.Drawing.Point(0,0)
Me.DgV_MulCapRowMerge1.MergeColumnNames = CType(resources.GetObject("DgV_MulCapRowMerge1.MergeColumnNames"),System.Collections.Generic.List(Of String))
Me.DgV_MulCapRowMerge1.Name = "DgV_MulCapRowMerge1"
Me.DgV_MulCapRowMerge1.RowTemplate.Height = 23
Me.DgV_MulCapRowMerge1.Size = New System.Drawing.Size(292,266)
Me.DgV_MulCapRowMerge1.TabIndex = 0
'
'Column1
'
Me.Column1.HeaderText = "Column1"
Me.Column1.Name = "Column1"
'
'Column2
'
Me.Column2.HeaderText = "Column2"
Me.Column2.Name = "Column2"
'
'Column3
'
Me.Column3.HeaderText = "Column3"
Me.Column3.Name = "Column3"
'
'Column4
'
Me.Column4.HeaderText = "Column4"
Me.Column4.Name = "Column4"
'
'Column5
'
Me.Column5.HeaderText = "Column5"
Me.Column5.Name = "Column5"
'
'Column6
'
Me.Column6.HeaderText = "Column6"
Me.Column6.Name = "Column6"
'
'Column7
'
Me.Column7.HeaderText = "Column7"
Me.Column7.Name = "Column7"
'
'Column8
'
Me.Column8.HeaderText = "Column8"
Me.Column8.Name = "Column8"
'
'Column9
'
Me.Column9.HeaderText = "Column9"
Me.Column9.Name = "Column9"
'
'Column10
'
Me.Column10.HeaderText = "Column10"
Me.Column10.Name = "Column10"
'
'Form2
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!,12.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(292,266)
Me.Controls.Add(Me.DgV_MulCapRowMerge1)
Me.Name = "Form2"
Me.Text = "Form2"
CType(Me.DgV_MulCapRowMerge1,System.ComponentModel.ISupportInitialize).EndInit()
Me.ResumeLayout(False)
End Sub
Friend WithEvents DgV_MulCapRowMerge1 As MulCapRowMergeDGV.DGV_MulCapRowMerge
Friend WithEvents Column1 As System.Windows.Forms.DataGridViewTextBoxColumn
Friend WithEvents Column2 As System.Windows.Forms.DataGridViewTextBoxColumn
Friend WithEvents Column3 As System.Windows.Forms.DataGridViewTextBoxColumn
Friend WithEvents Column4 As System.Windows.Forms.DataGridViewTextBoxColumn
Friend WithEvents Column5 As System.Windows.Forms.DataGridViewTextBoxColumn
Friend WithEvents Column6 As System.Windows.Forms.DataGridViewTextBoxColumn
Friend WithEvents Column7 As System.Windows.Forms.DataGridViewTextBoxColumn
Friend WithEvents Column8 As System.Windows.Forms.DataGridViewTextBoxColumn
Friend WithEvents Column9 As System.Windows.Forms.DataGridViewTextBoxColumn
Friend WithEvents Column10 As System.Windows.Forms.DataGridViewTextBoxColumn
End Class
'-----
'窗体内代码
Public Class Form2
'注意事项
Private Sub Form2_Load(ByVal sender As Object,ByVal e As System.EventArgs) Handles Me.Load
Dim StrCap As String()
ReDim StrCap(2)
' 不能让DgV_MulCapRowMerge1自动调整,不然增加的功能失效了
DgV_MulCapRowMerge1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing
'
'添加列
StrCap(0) = "一,二,三,四,Col5,Col6,COl7,Col8,Col9,Col10" '这是最下面一行列标题的内容,必须注意,个数一定和实际列对应
StrCap(1) = "演示,2Col2,3Col3,8Col8,Col10" '第2行的内容
StrCap(2) = "HCol1,HCol2,HCol5,HCol6,Col10" '第3行的内容
DgV_MulCapRowMerge1.ColumnSCaption = StrCap
DgV_MulCapRowMerge1.ColumnDeep = 3 '表示3行列标题,当设置为1时,ColumnSCaption属性设置失效
'添加数据
For iR As Integer = 0 To 20
Dim strs As String = ""
strs = strs & (iR / 3).ToString & "," & (iR / 4).ToString & "," & (iR / 5).ToString & "," & (iR / 6).ToString & "," & (iR / 7).ToString & "," & (iR / 8).ToString & "," & (iR / 9).ToString & "," & (iR / 10).ToString
DgV_MulCapRowMerge1.Rows.Add(strs.Split(","))
Next
'列标题的字体等可以利用 ColHeaderFont设置
' RowMergeViewClassa1.ColHeaderFont
'添加合并列
DgV_MulCapRowMerge1.MergeColumnNames.Add(DgV_MulCapRowMerge1.Columns(0).Name)
DgV_MulCapRowMerge1.MergeColumnNames.Add(DgV_MulCapRowMerge1.Columns(1).Name)
End Sub
End Class
附运行时的效果
原文链接:https://www.f2er.com/vb/261821.html