随笔-94  评论-56  文章-3  trackbacks-0

对于下面的表格数据,我们经常会见到,
20090601 00001 100 abc 1 sumisu
20080601 00001 120 abc 1 yasio
20070601 00001 150 def 1 toms
20050601 00001 190 efg 1 arabama


但有时候我们希望将同一列中内容相同的单元格合并,变成下面这样:
20090601 00001 100 abc 1 sumisu
20080601 120 yasio
20070601 150 def toms
20050601 190 efg arabama

那么该如何实现呢?
在网上调查了很多方法,也请教了很多人,虽然有一些解决方法,但都不是最理想的。
偶尔下载到一个例子,很漂亮地实现了这个功能,不过是C#的,于是我花了不少时间,终于将她用VB.net实现了,在这里与各位分享。

Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Drawing
Imports System.Drawing.Design
Imports System.Text
Imports System.Windows.Forms
Imports System.Collections
Imports System.Reflection
Imports System.Runtime.InteropServices

Public Class RowMergeView
    
Inherits DataGridView

    
Protected Overrides Sub OnCellPainting(ByVal e As DataGridViewCellPaintingEventArgs)

        
If e.RowIndex > -1 And e.ColumnIndex > -1 Then
            DrawCell(e)
        
End If

    
End Sub


    
'/ <summary>
    '/ DrawCell
    '/ </summary>
    '/ <param name="e"></param>
    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(e.CellStyle.BackColor)
        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
        
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)
            
IIf(curValue Is Nothing"", e.Value.ToString().Trim())
            
Dim curSelected As String = CType(Me.CurrentRow.Cells(e.ColumnIndex).Value, String)
            
IIf(curSelected Is Nothing""Me.CurrentRow.Cells(e.ColumnIndex).Value.ToString().Trim())
            
'If Not String.IsNullOrEmpty(curValue) Then
            Dim i As Integer
            
For i = e.RowIndex To Me.Rows.Count - 1 Step i + 1
                
If Me.Rows(i).Cells(e.ColumnIndex).Value.ToString().Equals(curValue) Then

                    DownRows 
= DownRows + 1
                    
If e.RowIndex <> i Then
                        cellwidth 
= cellwidth
                        
IIf(cellwidth < Me.Rows(i).Cells(e.ColumnIndex).Size.Width, cellwidth, Me.Rows(i).Cells(e.ColumnIndex).Size.Width)
                    
End If
                
Else
                    
Exit For
                
End If
            
Next

            
Dim j As Integer
            
For j = e.RowIndex To 0 Step j - 1
                
If Me.Rows(j).Cells(e.ColumnIndex).Value.ToString().Equals(curValue) Then

                    UpRows 
= UpRows + 1
                    
If e.RowIndex <> j Then
                        cellwidth 
= cellwidth
                        
IIf(cellwidth < Me.Rows(j).Cells(e.ColumnIndex).Size.Width, cellwidth, Me.Rows(j).Cells(e.ColumnIndex).Size.Width)
                    
End If
                
Else
                    
Exit For
                
End If
            
Next

            count 
= DownRows + UpRows - 1
            
If count < 2 Then
                
Return
            
End If
            
'End If
            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)

            PaintingFont(e, cellwidth, UpRows, DownRows, count)
            
If DownRows = 1 Then
                e.Graphics.DrawLine(gridLinePen, e.CellBounds.Left, e.CellBounds.Bottom 
- 1, e.CellBounds.Right - 1, e.CellBounds.Bottom - 1)
                count 
= 0
            
End If

            e.Graphics.DrawLine(gridLinePen, e.CellBounds.Right 
- 1, e.CellBounds.Top, e.CellBounds.Right - 1, e.CellBounds.Bottom - 1)

            e.Handled 
= True
        
End If
    
End Sub


    
'/ <summary>
    '/ PaintingFont
    '/ </summary>
    Private Sub PaintingFont(ByVal e As System.Windows.Forms.DataGridViewCellPaintingEventArgs, ByVal cellwidth As IntegerByVal UpRows As IntegerByVal DownRows As IntegerByVal count As Integer)
        
Dim fontBrush As SolidBrush = New SolidBrush(e.CellStyle.ForeColor)
        
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

        
If e.CellStyle.Alignment = DataGridViewContentAlignment.BottomCenter Then
            e.Graphics.DrawString(
CType(e.Value, String), e.CellStyle.Font, fontBrush, CType(e.CellBounds.X + (cellwidth - fontwidth) / 2Single), e.CellBounds.Y + cellheight * DownRows - fontheight)
        
ElseIf e.CellStyle.Alignment = DataGridViewContentAlignment.BottomLeft Then
            e.Graphics.DrawString(
CType(e.Value, String), e.CellStyle.Font, fontBrush, e.CellBounds.X, e.CellBounds.Y + cellheight * DownRows - fontheight)
        
ElseIf e.CellStyle.Alignment = DataGridViewContentAlignment.BottomRight Then
            e.Graphics.DrawString(
CType(e.Value, String), e.CellStyle.Font, fontBrush, e.CellBounds.X + cellwidth - fontwidth, e.CellBounds.Y + cellheight * DownRows - fontheight)
        
ElseIf e.CellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter Then
            e.Graphics.DrawString(
CType(e.Value, String), e.CellStyle.Font, fontBrush, CType(e.CellBounds.X + (cellwidth - fontwidth) / 2Single), CType(e.CellBounds.Y - cellheight * (UpRows - 1+ (cellheight * count - fontheight) / 2Single))
        
ElseIf e.CellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft Then
            e.Graphics.DrawString(
CType(e.Value, String), e.CellStyle.Font, fontBrush, e.CellBounds.X, CType(e.CellBounds.Y - cellheight * (UpRows - 1+ (cellheight * count - fontheight) / 2Single))
        
ElseIf e.CellStyle.Alignment = DataGridViewContentAlignment.MiddleRight Then
            e.Graphics.DrawString(
CType(e.Value, String), e.CellStyle.Font, fontBrush, e.CellBounds.X + cellwidth - fontwidth, CType(e.CellBounds.Y - cellheight * (UpRows - 1+ (cellheight * count - fontheight) / 2Single))
        
ElseIf e.CellStyle.Alignment = DataGridViewContentAlignment.TopCenter Then
            e.Graphics.DrawString(
CType(e.Value, String), e.CellStyle.Font, fontBrush, e.CellBounds.X + CType((cellwidth - fontwidth) / 2Single), e.CellBounds.Y - cellheight * (UpRows - 1))
        
ElseIf e.CellStyle.Alignment = DataGridViewContentAlignment.TopLeft Then
            e.Graphics.DrawString(
CType(e.Value, String), e.CellStyle.Font, fontBrush, e.CellBounds.X, e.CellBounds.Y - cellheight * (UpRows - 1))
        
ElseIf e.CellStyle.Alignment = DataGridViewContentAlignment.TopRight Then
            e.Graphics.DrawString(
CType(e.Value, String), e.CellStyle.Font, fontBrush, e.CellBounds.X + cellwidth - fontwidth, e.CellBounds.Y - cellheight * (UpRows - 1))
        
Else
            e.Graphics.DrawString(
CType(e.Value, String), e.CellStyle.Font, fontBrush, e.CellBounds.X + CType((cellwidth - fontwidth) / 2Single), CType(e.CellBounds.Y - cellheight * (UpRows - 1+ (cellheight * count - fontheight) / 2Single))
        
End If
    
End Sub


    
'/ <summary>
    '/ MergeColumnNames
    '/ </summary>
    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

    
Private _mergecolumnname As List(Of String= New List(Of String)()

End Class


Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Drawing
Imports System.Text
Imports System.Windows.Forms


Public Class Form1

    
Public Sub New()
        InitializeComponent()
        
Dim dt As DataTable = New DataTable()
        
Dim i As Integer
        dt.Columns.Add(
"1")
        dt.Columns.Add(
"2")
        dt.Columns.Add(
"3")
        dt.Columns.Add(
"4")
        dt.Columns.Add(
"5")
        dt.Columns.Add(
"6")
        dt.Rows.Add(
"20090601""00001""100""abc""1""sumisu")
        dt.Rows.Add(
"20080601""00001""120""abc""1""yasio")
        dt.Rows.Add(
"20070601""00001""150""def""1""toms")
        dt.Rows.Add(
"20050601""00001""190""efg""1""arabama")
        
Me.rowMergeView1.DataSource = dt
        
Me.rowMergeView1.ColumnHeadersHeight = 20
        
Me.rowMergeView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing
        
For i = 1 To dt.Columns.Count
            
Me.rowMergeView1.MergeColumnNames.Add("Column" & i)
        
Next
    
End Sub

End Class


<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial 
Class Form1
    
Inherits System.Windows.Forms.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(Form1))
        
Me.Panel1 = New System.Windows.Forms.Panel
        
Me.Button1 = New System.Windows.Forms.Button
        
Me.rowMergeView1 = New testMearge.RowMergeView
        
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.Panel1.SuspendLayout()
        
CType(Me.rowMergeView1, System.ComponentModel.ISupportInitialize).BeginInit()
        
Me.SuspendLayout()
        
'
        'Panel1
        '
        Me.Panel1.Controls.Add(Me.Button1)
        
Me.Panel1.Dock = System.Windows.Forms.DockStyle.Bottom
        
Me.Panel1.Location = New System.Drawing.Point(0312)
        
Me.Panel1.Name = "Panel1"
        
Me.Panel1.Size = New System.Drawing.Size(59531)
        
Me.Panel1.TabIndex = 1
        
'
        'Button1
        '
        Me.Button1.Location = New System.Drawing.Point(4995)
        
Me.Button1.Name = "Button1"
        
Me.Button1.Size = New System.Drawing.Size(7523)
        
Me.Button1.TabIndex = 0
        
Me.Button1.Text = "Button1"
        
Me.Button1.UseVisualStyleBackColor = True
        
'
        'rowMergeView1
        '
        Me.rowMergeView1.AllowUserToAddRows = False
        
Me.rowMergeView1.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill
        
Me.rowMergeView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize
        
Me.rowMergeView1.Columns.AddRange(New System.Windows.Forms.DataGridViewColumn() {Me.Column1, Me.Column2, Me.Column3, Me.Column4, Me.Column5, Me.Column6})
        
Me.rowMergeView1.Dock = System.Windows.Forms.DockStyle.Fill
        
Me.rowMergeView1.Location = New System.Drawing.Point(00)
        
Me.rowMergeView1.MergeColumnNames = CType(resources.GetObject("rowMergeView1.MergeColumnNames"), System.Collections.Generic.List(Of String))
        
Me.rowMergeView1.Name = "rowMergeView1"
        
Me.rowMergeView1.RowTemplate.Height = 21
        
Me.rowMergeView1.Size = New System.Drawing.Size(595343)
        
Me.rowMergeView1.TabIndex = 0
        
'
        'Column1
        '
        Me.Column1.DataPropertyName = "1"
        
Me.Column1.HeaderText = "日期"
        
Me.Column1.Name = "Column1"
        
'
        'Column2
        '
        Me.Column2.DataPropertyName = "2"
        
Me.Column2.HeaderText = "代码"
        
Me.Column2.Name = "Column2"
        
'
        'Column3
        '
        Me.Column3.DataPropertyName = "3"
        
Me.Column3.HeaderText = "价格"
        
Me.Column3.Name = "Column3"
        
'
        'Column4
        '
        Me.Column4.DataPropertyName = "4"
        
Me.Column4.HeaderText = "备注"
        
Me.Column4.Name = "Column4"
        
'
        'Column5
        '
        Me.Column5.DataPropertyName = "5"
        
Me.Column5.HeaderText = "标志"
        
Me.Column5.Name = "Column5"
        
'
        'Column6
        '
        Me.Column6.DataPropertyName = "6"
        
Me.Column6.HeaderText = "更新者"
        
Me.Column6.Name = "Column6"
        
'
        'Form1
        '
        Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 12.0!)
        
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
        
Me.ClientSize = New System.Drawing.Size(595343)
        
Me.Controls.Add(Me.Panel1)
        
Me.Controls.Add(Me.rowMergeView1)
        
Me.Name = "Form1"
        
Me.Text = "Form1"
        
Me.Panel1.ResumeLayout(False)
        
CType(Me.rowMergeView1, System.ComponentModel.ISupportInitialize).EndInit()
        
Me.ResumeLayout(False)

    
End Sub

    
Friend WithEvents rowMergeView1 As RowMergeView
    
Friend WithEvents Panel1 As System.Windows.Forms.Panel
    
Friend WithEvents Button1 As System.Windows.Forms.Button
    
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

End Class


运行结果如下:
 
原C#代码:
/Files/xiekai-blog/DataGridView.rar
posted on 2009-06-17 12:36 小言身寸 阅读(12642) 评论(18)  编辑  收藏 所属分类: . NET 开发

评论:
# re: vb.net中dataGridView的单元格的合并 2010-01-20 14:09 | JonesVale
请问以下代码是如何所得 ,请指点,谢谢!
'
'rowMergeView1
'
Me.rowMergeView1.AllowUserToAddRows = False
Me.rowMergeView1.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill
Me.rowMergeView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize
Me.rowMergeView1.Columns.AddRange(New System.Windows.Forms.DataGridViewColumn() {Me.Column1, Me.Column2, Me.Column3, Me.Column4, Me.Column5, Me.Column6})
Me.rowMergeView1.Dock = System.Windows.Forms.DockStyle.Fill
Me.rowMergeView1.Location = New System.Drawing.Point(0, 0)
Me.rowMergeView1.MergeColumnNames = CType(resources.GetObject("rowMergeView1.MergeColumnNames"), System.Collections.Generic.List(Of String))
Me.rowMergeView1.Name = "rowMergeView1"
Me.rowMergeView1.RowTemplate.Height = 21
Me.rowMergeView1.Size = New System.Drawing.Size(595, 343)
Me.rowMergeView1.TabIndex = 0

  回复  更多评论
  
# re: vb.net中dataGridView的单元格的合并 2010-01-21 14:44 | JonesVale
中心是这一句
Me.rowMergeView1.MergeColumnNames = CType(resources.GetObject("rowMergeView1.MergeColumnNames"), System.Collections.Generic.List(Of String))
  回复  更多评论
  
# re: vb.net中dataGridView的单元格的合并 2010-04-26 15:53 | youke
以上代码在vs2008中需要将and改为andalso  回复  更多评论
  
# re: vb.net中dataGridView的单元格的合并 2010-12-16 19:56 | pxfinal
为什么我试了一下,总是显示“为将对象引用到实例”,当添加
Me.RowMergeView1.MergeColumnNames.Add("Column" & i)这个时候

Set(ByVal Value As Collection)
_mergecolumnname = Value ‘value=nothing
End Set
这样就将这个属性再次赋值为空了, 无法添加。  回复  更多评论
  
# re: vb.net中dataGridView的单元格的合并 2011-03-18 14:27 | xiekai
你好可能把源码发给我吗?
邮箱:niaiyaolong@163.com
谢谢!  回复  更多评论
  
# re: vb.net中dataGridView的单元格的合并 2011-04-16 21:07 | xinbo
Protected Overrides Sub OnCellPainting(ByVal e As DataGridViewCellPaintingEventArgs) '

If e.RowIndex > -1 AndAlso e.ColumnIndex > -1 AndAlso e.Value IsNot Nothing(此处添加判断) Then
DrawCell(e)
End If

End Sub

修改第二处:

For i = e.RowIndex To Me.Rows.Count - 1 Step i + 1
If Me.Rows(i).Cells(e.ColumnIndex).Value Is Nothing Then
Exit For
End If ‘添加一个判断
If Me.Rows(i).Cells(e.ColumnIndex).Value.ToString().Equals(curValue) Then

DownRows = DownRows + 1
If e.RowIndex <> i Then
cellwidth = cellwidth
IIf(cellwidth < Me.Rows(i).Cells(e.ColumnIndex).Size.Width, cellwidth, Me.Rows(i).Cells(e.ColumnIndex).Size.Width)
End If
Else
Exit For
End If
Next  回复  更多评论
  
# re: vb.net中dataGridView的单元格的合并 2011-05-10 16:50 | 阿胡
你好!可發一份源碼給我嗎?非常感謝!
nineheads@tom.com
  回复  更多评论
  
# re: vb.net中dataGridView的单元格的合并 2011-05-23 16:49 | 阿伍
你好,自学很久了始终不入门,能给份源码。非常感谢!邮箱:443272678@QQ.com  回复  更多评论
  
# re: vb.net中dataGridView的单元格的合并 2011-06-12 18:23 | acicd
你好可能把源码发给我吗?
acicd@sohu.com  回复  更多评论
  
# re: vb.net中dataGridView的单元格的合并[未登录] 2012-11-23 16:55 | KK
請問可以寄一份 VB 的源碼嗎?
謝謝您~
fwt0209@gmail.com  回复  更多评论
  
# re: vb.net中dataGridView的单元格的合并 2013-02-06 09:27 | icemna
Me.RowMergeView1.MergeColumnNames = New List(Of String)
For i = 1 To dt.Columns.Count
Me.rowMergeView1.MergeColumnNames.Add("Column" & i)
Next
对MergeColumnNames赋值(Add)之前要实例化的。l
  回复  更多评论
  
# re: vb.net中dataGridView的单元格的合并 2013-02-23 11:03 | 0514
請問可以寄一份 VB 的源碼嗎?
謝謝您~
邮箱:431093685@QQ.com   回复  更多评论
  
# re: vb.net中dataGridView的单元格的合并 2013-07-08 12:32 | billycwy
您好,请问可以寄一份VB.net 的源码吗?
万分感谢
谢谢您了
邮箱:8230220@qq.com  回复  更多评论
  
# re: vb.net中dataGridView的单元格的合并 2013-07-29 19:24 | 芙蓉妮
期盼许久了......
原先是用vb做的系统,无法实现单元格合并问题,近期刚刚改学vb.net,看到楼主已经实现了此功能我欣喜若狂,希望能拜读到楼主的源码,万分感谢
frownies@139.com
  回复  更多评论
  
# re: vb.net中dataGridView的单元格的合并 2013-10-30 17:10 | 112
为什么我选中合并单元格的最后一行,合并单元格的内容就会消失  回复  更多评论
  
# re: vb.net中dataGridView的单元格的合并 2013-11-09 14:10 | Surfing
可以寄一份vb.net源碼給我嗎?
ms101690@pchome.com.tw  回复  更多评论
  
# re: vb.net中dataGridView的单元格的合并 2014-11-18 11:08 | uyfghfv
你好,可以寄一份源碼給我嗎?keobo.wang@deltaww.com.cn  回复  更多评论
  
# re: vb.net中dataGridView的单元格的合并 2015-08-28 09:07 | ヒツ
合并的单元格无法选中,如何解决,还有我想在合并的单元个里绘checkbox怎么弄  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航:
博客园   IT新闻   Chat2DB   C++博客   博问