Click here to Skip to main content
15,396,106 members
Articles / Desktop Programming / Windows Forms
Posted 23 Apr 2009


110 bookmarked

MergedDataGridView Control

Rate me:
Please Sign up or sign in to vote.
4.81/5 (28 votes)
23 Apr 2009CPOL2 min read
A DataGridView control that allows to show some extra information in a merged row. Uses Visual Basic.NET 2008 and Framework 3.5.



As we all know, the DataGridView control doesn't allow us to merge cells, and if we think a little on that, we can ask ourselves the question, "Why?” Well, the DataGridView is bound to a data source (even if you don't define that), and each cell represents a field in a record, so what field will that merged cell belong to? Maybe, it was because of this that Microsoft didn't include this feature. But, sometimes, we may want to show some extra information, and the only solution is to popup a form/message box, or “steal” some space in the current form and fill it with textboxes, combo’s, etc.

The goal of this customization is to show some extra information in a DataGridView. It basically uses a RichTextBox that is inserted in the grid and sized according to the parent row. The parent row must have a unique ID that will be the textbox name. This will then be used to size and position the RichTextBox in the right place.

I have also included some icon animation and grid customization to improve the end look.

Using the code

To start, you must include the class MergedDataGridView in your application. After you build the project, the MergedDataGridView control will be available in the toolbox. Then, just drag it to your form.

Next, you need to define the custom properties for the MergedDataGridView:

With Me.MergedDataGridView1
    ' Define the datasource
    .DataSource = ds.Tables(0).DefaultView

    ' Custom definitions for the RichTextBox
    .StartColumnIndex = 1
    .EndColumnIndex = 7
    .RowHeight = 60

    ' Custom definitions for the DataGridView
    .AllowUserToAddRows = False
    .AllowUserToDeleteRows = False

    .RowsDefaultCellStyle.BackColor = Color.White
    .AlternatingRowsDefaultCellStyle.BackColor = Color.AliceBlue

End With 

After this, you can include the two DataGridViewImageColumns that will be used to show the RichTextBox and to display a MessageBox containing the information.

' Create an image column in the datagrid that will open the merged row
Dim ImageColumn1 As New DataGridViewImageColumn
ImageColumn1.DefaultCellStyle.Alignment = DataGridViewContentAlignment.TopCenter
ImageColumn1.Image = My.Resources.DownArrow
ImageColumn1.Width = 25

' Create an image column in the datagrid that will open an extra window
Dim ImageColumn2 As New DataGridViewImageColumn
ImageColumn2.DefaultCellStyle.Alignment = DataGridViewContentAlignment.TopCenter
ImageColumn2.Image = My.Resources.Info
ImageColumn2.Width = 25

' Add the two columns to the datagridview
Me.MergedDataGridView1.Columns.AddRange(New _
   DataGridViewImageColumn() {ImageColumn1, ImageColumn2})

Finally, in the CellMouseClick event, check to see if the user clicked on the right column; if so, add the new row:

' Add a new row in the correct postion (e.RowIndex + 1)
Dim rowPos As Integer = e.RowIndex + 1

Dim dv As DataView = Me.MergedDataGridView1.DataSource
Dim row As DataRow = dv.Table.NewRow()
dv.Table.Rows.InsertAt(row, rowPos)

' Get the text from the hidden columns that will be used to fill the RichTextBox
Dim mergedRowText As New System.Text.StringBuilder
mergedRowText.AppendLine(Me.MergedDataGridView1("Description", e.RowIndex).Value.ToString)
mergedRowText.AppendLine(Me.MergedDataGridView1("Link", e.RowIndex).Value.ToString)

' Call the AddMergedRow sub
Me.MergedDataGridView1.AddMergedRow(rowPos, mergedRowText.ToString)

Or delete it:

' Remove the row from the datasource
Dim rowPos As Integer = e.RowIndex + 1

Dim dv As DataView = Me.MergedDataGridView1.DataSource

' Call the RemoveMergedRow sub
Me.MergedDataGridView1.RemoveMergedRow(Me.MergedDataGridView1(0, _

The other code used in the form, as you can see in the attached example, is for validation, error handling, and generic animation.

Looking at the control


The control has only two methods: AddMergedRow and RemoveMergedRow, and three properties. The properties just get the indication of the column where the RichTextBox will start, end, and what height it will have.

The AddMergedRow looks for the number (the ID) of the previous row, that will be the parent one, and creates a new RichTextBox in the new row, with that ID as the name.

''' <summary>
''' Adds a new row with a merged cell using a richtextbox
''' </summary>
''' <param name="rowIndex">Index where the row will be added</param>
''' <param name="cellText">Text that will be displayed on the RichTextBox</param>
''' <remarks></remarks>
Public Sub AddMergedRow(ByVal rowIndex As Integer, ByVal cellText As String)



        ' Defines the location/size of the textbox
        Dim x As Integer = _
            Me.GetColumnDisplayRectangle(Me.StartColumnIndex, False).Left + 1
        Dim y As Integer = Me.GetRowDisplayRectangle(rowIndex, False).Top
        Dim w As Integer = _
            Me.GetColumnDisplayRectangle(Me.EndColumnIndex, False).Right - x - 2
        Dim h As Integer = Me.GetRowDisplayRectangle(rowIndex, False).Size.Height - 1

        ' Gets the ID from the previous row, that will be used for the name
        ' of the textbox. This ID will be used to find the control for the row
        Dim parentRowID As Integer = Me(0, rowIndex - 1).Value

        ' Creates a new textbox and place it in the right position
        Dim rtb As New RichTextBox
        With rtb
            .Name = parentRowID
            .Text = cellText
            .Multiline = True
            .BorderStyle = BorderStyle.None
            .ScrollBars = ScrollBars.Vertical
            .ReadOnly = True
            .Font = New Font(Me.DefaultCellStyle.Font, Me.DefaultCellStyle.Font.Style)
            .SetBounds(x, y, w, h)
        End With
        ' Define the same color for the RichTextBox as the row color
        rtb.BackColor = Me(0, rowIndex).InheritedStyle.BackColor

        ' Define the row height
        Me.Rows(rowIndex).Height = Me.RowHeight

        ' Define a new image for the imagecell (up arrow)
        Dim arrow As DataGridViewImageCell = Me(Me.ColumnCount - 2, rowIndex - 1)
        arrow.Value = My.Resources.UpArrow

    Catch ex As Exception
        Throw New ArgumentException(ex.Message)

    End Try

End Sub

The second method, RemoveMergedRow, looks for the parent row and removes it from the grid.

''' <summary>
''' Removes the cell (RichTextBox) from the DataGridView
''' </summary>
''' <param name="rowID">ID of the row</param>
''' <remarks></remarks>
Public Sub RemoveMergedRow(ByVal rowID As Integer)


        ' Find the control in the DataGridView and remove it
        Dim ctrl() As Control = Me.Controls.Find(rowID.ToString, False)
        If ctrl.Length = 1 Then
        End If

        ' Define a new image for the imagecell (down arrow)
        Dim arrow As DataGridViewImageCell = Me(Me.ColumnCount - 2, Me.CurrentRow.Index)
        arrow.Value = My.Resources.DownArrow

    Catch ex As Exception
        Throw New ArgumentException(ex.Message)

    End Try

End Sub

The Paint event arranges the position of the RichTextBoxes, and adjusts the size.

Since it’s not easy to calculate the positions and keep the empty rows below the parent rows after you sort it, I have turned sorting off in the ColumnAdded event.

Points of interest

This control not only shows some extra information on a DataGridView control, but also demonstrates how to customize the grid and handle row positioning, which may be useful for other projects.

I really hope that this can help improve your projects, or help you get some new ideas.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Software Developer
Portugal Portugal
Jorge Paulino
Microsoft Visual Basic MVP
Portuguese Software Developer

Comments and Discussions

QuestionNice post Pin
Tridip Bhattacharjee12-Dec-13 21:46
professionalTridip Bhattacharjee12-Dec-13 21:46 
GeneralGood and simple replacement for an Outlook style listview Pin
Francisco J. Rodríguez12-Feb-12 3:36
MemberFrancisco J. Rodríguez12-Feb-12 3:36 
GeneralUpdate?? Pin
dherrmann4-Jun-11 23:48
Memberdherrmann4-Jun-11 23:48 
GeneralRe: Update?? Pin
jpaulino5-Jun-11 0:01
Memberjpaulino5-Jun-11 0:01 
GeneralRe: Update?? Pin
dherrmann5-Jun-11 0:07
Memberdherrmann5-Jun-11 0:07 
GeneralThanks Pin
YZK30-Mar-11 0:00
MemberYZK30-Mar-11 0:00 
Generaladd columns Pin
creativesoul3-Dec-10 2:23
Membercreativesoul3-Dec-10 2:23 
GeneralFine component! Pin
Marcelo Ricardo de Oliveira8-Dec-09 7:23
mvaMarcelo Ricardo de Oliveira8-Dec-09 7:23 
GeneralRe: Fine component! Pin
jpaulino9-Dec-09 10:06
Memberjpaulino9-Dec-09 10:06 
GeneralParabens - Congratulations Pin
Sc0rp1026-May-09 9:05
MemberSc0rp1026-May-09 9:05 
GeneralRe: Parabens - Congratulations Pin
jpaulino26-May-09 9:10
Memberjpaulino26-May-09 9:10 
Generalsome improvements Pin
Mr.PoorEnglish18-May-09 10:37
MemberMr.PoorEnglish18-May-09 10:37 
GeneralRe: some improvements Pin
jpaulino18-May-09 10:51
Memberjpaulino18-May-09 10:51 
GeneralRe: some improvements [modified] Pin
Bib3477021-May-09 1:16
MemberBib3477021-May-09 1:16 
GeneralBug fix + add on + question [modified] Pin
Bib347703-May-09 5:25
MemberBib347703-May-09 5:25 
GeneralRe: Bug fix + add on + question Pin
jpaulino18-May-09 10:55
Memberjpaulino18-May-09 10:55 
GeneralRe: Bug fix + add on + question Pin
Bib3477019-May-09 10:12
MemberBib3477019-May-09 10:12 
GeneralRe: Bug fix + add on + question Pin
jpaulino19-May-09 10:19
Memberjpaulino19-May-09 10:19 
GeneralRe: Bug fix + add on + question Pin
Bib3477019-May-09 10:51
MemberBib3477019-May-09 10:51 
GeneralWow Pin
pluniewski27-Apr-09 20:25
Memberpluniewski27-Apr-09 20:25 
GeneralRe: Wow Pin
jpaulino27-Apr-09 22:04
Memberjpaulino27-Apr-09 22:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.