编程过程中经常遇到数据合并和多行标头的情况,以前用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
最后:代码我资源上传,需要的下载吧
附运行时的效果
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|