DataGridView Custom Headers in VB.NET






4.56/5 (15 votes)
How to give Custom Headers to your DataGridView
Here's a screen shot of what you will get by using this code:

Introduction
This code came out as an elaboration of Custom draw datagridviewcolumnheader (like Excel 2007) by Andy32.
Normally, a DataGridView
control won't allow you to set a background image for its column headers. This code will do that, in a very easy way.
I made this just to simplify what has already been done by the original author.
I supplied an image, which is a stripe (1 pixel wide), to use a background. You don't need more, because it will be stretched to fill the whole columnheader
.
Now, since it is a semi-transparent PNG, you'll see the color of the Columheader
. By doing so, you won't need to supply a different image for each colour you'd like to paint your Headers - you just change the ColumnHeadersDefaultCellStyle.BackColor
property and you're done.
It couldn't be any easier, I think.
Background
As the original article, this code illustrates how to custom draw a DataGridView
Column Headers.
My version is just an optimized version of the original, with much less code and a small improvement (the mentioned small-sized transparent image that lets the underlying color be seen through).
There is very little code: an enumeration (a set of grouped constants), a method and its call inside an event of the DataGridView
. Nothing more than this!!
Oh, well, I forgot to mention that a little bit of initialization code is required (here I do that directly in the Form's Load
event handler, but you can put it into a method and call that method from the Load
event).
Private Sub frmMain_Load(ByVal sender As Object, ByVal e As EventArgs) _
Handles Me.Load
' Init.
' Set up the Header Color and Font.
With dgvData.ColumnHeadersDefaultCellStyle
.Alignment = DataGridViewContentAlignment.MiddleCenter
.BackColor = Color.DarkRed
.ForeColor = Color.Gold
.Font = New Font(.Font.FontFamily, .Font.Size, _
.Font.Style Or FontStyle.Bold, GraphicsUnit.Point)
End With
' Fill in some Text.
For i As Int32 = 0 To 20
Dim arrStrings As String()
arrStrings = New String() _
{ _
i.ToString, "Text " & i.ToString, i.ToString, _
"Text " & i.ToString, i.ToString _
}
dgvData.Rows.Add(arrStrings)
arrStrings = Nothing
Next i
End Sub
Just to put some data into the DataGridView
and to set the Color
for its column headers.
Using the Code
Inside the CellPainting
event of the DataGridView
, call the supplied GridDrawCustomHeaderColumns
method (feel free to shorten the name, if you want):
Private Sub dgvData_CellPainting(ByVal sender As Object, _
ByVal e As DataGridViewCellPaintingEventArgs) _
Handles dgvData.CellPainting
' Only the Header Row (which Index is -1) is to be affected.
If e.RowIndex = -1 Then
GridDrawCustomHeaderColumns(dgvData, e, _
My.Resources.Button_Gray_Stripe_01_050, _
DGVHeaderImageAlignments.Stretch)
End If
End Sub
The code above will override the normal CellPainting
with the code contained in our method:
Private Sub GridDrawCustomHeaderColumns(ByVal dgv As DataGridView, _
ByVal e As DataGridViewCellPaintingEventArgs, ByVal img As Image, _
ByVal Style As DGVHeaderImageAlignments)
' All of the graphical Processing is done here.
Dim gr As Graphics = e.Graphics
' Fill the BackGround with the BackGroud Color of Headers.
' This step is necessary, for transparent images, or what's behind
' would be painted instead.
gr.FillRectangle( _
New SolidBrush(dgv.ColumnHeadersDefaultCellStyle.BackColor), _
e.CellBounds)
If img IsNot Nothing Then
Select Case Style
Case DGVHeaderImageAlignments.FillCell
gr.DrawImage( _
img, e.CellBounds.X, e.CellBounds.Y, _
e.CellBounds.Width, e.CellBounds.Height)
Case DGVHeaderImageAlignments.SingleCentered
gr.DrawImage(img, _
((e.CellBounds.Width - img.Width) \ 2) + _
e.CellBounds.X, _
((e.CellBounds.Height - img.Height) \ 2) + _
e.CellBounds.Y, _
img.Width, img.Height)
Case DGVHeaderImageAlignments.SingleLeft
gr.DrawImage(img, e.CellBounds.X, _
((e.CellBounds.Height - img.Height) \ 2) + _
e.CellBounds.Y, _
img.Width, img.Height)
Case DGVHeaderImageAlignments.SingleRight
gr.DrawImage(img, _
(e.CellBounds.Width - img.Width) + _
e.CellBounds.X, _
((e.CellBounds.Height - img.Height) \ 2) + _
e.CellBounds.Y, _
img.Width, img.Height)
Case DGVHeaderImageAlignments.Tile
' ***********************************************
' To correct: It should display
' just a stripe of images,
' long as the whole header,
' but centered in the header's
' height.
' This code WON'T WORK.
' Any one got any better solution?
'Dim rect As New Rectangle(e.CellBounds.X, _
' ((e.CellBounds.Height - img.Height) \ 2), _
' e.ClipBounds.Width, _
' ((e.CellBounds.Height \ 2 + img.Height \ 2)))
'Dim br As New TextureBrush_
'(img, Drawing2D.WrapMode.Tile, _
' rect)
' ************************************************
' This one works... but poorly
' (the image is repeated
' vertically, too).
Dim br As New TextureBrush_
(img, Drawing2D.WrapMode.Tile)
gr.FillRectangle(br, e.ClipBounds)
Case Else
gr.DrawImage( _
img, e.CellBounds.X, e.CellBounds.Y, _
e.ClipBounds.Width, e.CellBounds.Height)
End Select
End If
'e.PaintContent(e.CellBounds)
If e.Value Is Nothing Then
e.Handled = True
Return
End If
Using sf As New StringFormat
With sf
Select Case dgv.ColumnHeadersDefaultCellStyle.Alignment
Case DataGridViewContentAlignment.BottomCenter
.Alignment = StringAlignment.Center
.LineAlignment = StringAlignment.Far
Case DataGridViewContentAlignment.BottomLeft
.Alignment = StringAlignment.Near
.LineAlignment = StringAlignment.Far
Case DataGridViewContentAlignment.BottomRight
.Alignment = StringAlignment.Far
.LineAlignment = StringAlignment.Far
Case DataGridViewContentAlignment.MiddleCenter
.Alignment = StringAlignment.Center
.LineAlignment = StringAlignment.Center
Case DataGridViewContentAlignment.MiddleLeft
.Alignment = StringAlignment.Near
.LineAlignment = StringAlignment.Center
Case DataGridViewContentAlignment.MiddleRight
.Alignment = StringAlignment.Far
.LineAlignment = StringAlignment.Center
Case DataGridViewContentAlignment.TopCenter
.Alignment = StringAlignment.Center
.LineAlignment = StringAlignment.Near
Case DataGridViewContentAlignment.TopLeft
.Alignment = StringAlignment.Near
.LineAlignment = StringAlignment.Near
Case DataGridViewContentAlignment.TopRight
.Alignment = StringAlignment.Far
.LineAlignment = StringAlignment.Near
End Select
' This part could be handled...
'Select Case dgv.ColumnHeadersDefaultCellStyle.WrapMode
' Case DataGridViewTriState.False
' .FormatFlags = StringFormatFlags.NoWrap
' Case DataGridViewTriState.NotSet
' .FormatFlags = StringFormatFlags.NoWrap
' Case DataGridViewTriState.True
' .FormatFlags = _
StringFormatFlags.FitBlackBox
'End Select
.HotkeyPrefix = Drawing.Text.HotkeyPrefix.None
.Trimming = StringTrimming.None
End With
With dgv.ColumnHeadersDefaultCellStyle
gr.DrawString(e.Value.ToString, .Font, _
New SolidBrush(.ForeColor), e.CellBounds, sf)
End With
End Using
e.Handled = True
End Sub
So, what it does, basically is to:
Draw the background color, overlay an image over it, draw the text.
The way it aligns text is how you would draw the text on any other control: check how user wants the text to be aligned and operate accordingly with the StringFormat
object you'll use in combination with the DrawString
method.
There's two properties to do this: Alignment
(horizontally) and LineAlignment
(vertically); and three values Near
(Left or Up), Far
(Right or Down), and Center
(Middle).
The combination of these properties with their values gives the nine possible alignments for a text.
The way it draws the image can be tricky, so...
... you'll notice a section, in the above code, delimited by two "all asterisks" comment lines.
That's room for improvements (surely due to my misinterpretation of the DrawImage
method).
I hope that other programmers will find this code useful as per their needs.
Let me know how you make this code better.
History
- 9th March, 2009: Initial post