Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Custom draw datagridviewcolumnheader (like excel 2007)

0.00/5 (No votes)
28 Jan 2007 1  
Overriding the cellpaint event of the datagridview to give it a gradient background

Sample Image - GradientColumnheader.png

Introduction

As I'm working quite some time now with the code project as a reliable source which I could depend on improving my developping skills, I decided it's time to do my own posting. I recently downloaded the new Office 2007 and I'm quite excited about the new layout. I work a lot with data and wanted to improve the interface of the datagridview, with columnheaders similar to the ones found in Excel 2007, with a bit of gradient colour in it.

Overview

I first experimented with the columnheader and figured out I had to switch of the EnableHeadersVisibleStyle option in order to get a color as background. However, a single color did not quite look like the gradient headers found in Office 2007.

So, I went further down and found the solution in overriding the cell paint event of the datagridview. Columnheaders have a rowindex of -1, which makes it easy to limit the method to be executed only on the columnheader. There are quite a few option you can choose when overriding the cell paint event in order to get a custom drawn columnheader. I have chosen to make use of the graphics object and the drawimage method, which allowed me to use an image resource as background. It opens possibilities for re-using the code as part of a skinning project, but that was beyond my needs for now.

Because of the use of the graphics object, there are some alternatives for custom painting the datagridview columnheader, like for instance using a lineargradientbrush. To do that, simply replace the drawimage part of the method with the fillrectangle method.

The code

In the opening event of the form, I put some code to fill the datagridview. We'll skip that part here.

You could choose for creating a class which inherits from the datagridview and override the cell paint event there, or you could just override the event in the form class (I have chosen the last option for the example).

The code looks like this :

Private Sub DataGridView1_CellPainting(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellPaintingEventArgs) Handles DataGridView1.CellPaintingIf e.RowIndex = -1 ThenDim img As ImageMy.Resources.HeaderDim format1 As StringFormatNew StringFormatDim ef1 As SizeF = e.Graphics.MeasureString(e.Value, Me.Font, New SizeF(CType(e.CellBounds.Width, Single), CType(e.CellBounds.Height, Single)), format1)Dim txts As SizeDim txtr As Rectangle = e.CellBoundsDim brush2 As BrushNew StringFormatNew SolidBrush(Color.FromArgb(21, 66, 139))Me.Font, brush2, CType(txtr, RectangleF), format1)Dim recBorder As New Rectangle(e.CellBounds.X - 1, e.CellBounds.Y, e.CellBounds.Width, e.CellBounds.Height - 1)TrueEnd IfEnd Sub

img =

TekenAchtergrond(e.Graphics, img, e.CellBounds, 1)

format1 =

format1.HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.Show

txts = Drawing.Size.Empty

txts = Drawing.Size.Ceiling(ef1)

e.CellBounds.Inflate(-4, -4)

txtr = HAlignWithin(txts, txtr, ContentAlignment.MiddleCenter)

txtr = VAlignWithin(txts, txtr, ContentAlignment.MiddleCenter)

format1 =

format1.HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.Show

brush2 =

e.Graphics.DrawString(e.Value,

brush2.Dispose()

e.Graphics.DrawRectangle(Pens.LightSlateGray, recBorder)

e.Handled =

In the cellpaint event, I get my header background from the resource files and pass it along with the graphics object, the drawing rectangle and an index parameter which can be used if the image file contains more than one template, for skinning purposes, to the Tekenachtergrond (I'm from Belgium and tekenachtergrond is Dutch, means something like draw background) method. As I only use one template in this example, I set the index to 1.

The method, which is based on an article I found on this site which handles the skinning of controls (link to the article), along with some extra alignment methods and variables, looks like this :

Public

* oWidth)

r1 =

r2 =

g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)

r1 =

- (lr.Top - lr.Bottom)))

r2 =

- (lr.Top - lr.Bottom)))

= 0)

r1.Height = (r1.Height - 1)

g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)

r1 =

+ (obj.Height - lr.Bottom)), oWidth, lr.Bottom)

r2 =

+ (r.Height - lr.Bottom)), r.Width, lr.Bottom)

g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)

r1 =

r2 =

g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)

r1 =

- (lr.Left - lr.Right)), obj.Height)

r2 =

- (lr.Left - lr.Right)), r.Height)

g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)

r1 =

+ (oWidth - lr.Right)), y, lr.Right, obj.Height)

r2 =

+ (r.Width - lr.Right)), y1, lr.Right, r.Height)

g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)

r1 =

* oWidth), 0, oWidth, (obj.Height - 1))

g.DrawImage(obj,

r1 =

r2 =

g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)

r1 =

+ (obj.Height - lr.Bottom)), lr.Left, lr.Bottom)

r2 =

+ (r.Height - lr.Bottom)), lr.Left, lr.Bottom)

g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)

r1 =

- (lr.Top - lr.Bottom)))

r2 =

- (lr.Top - lr.Bottom)))

g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)

r1 =

- (lr.Left - lr.Right)), lr.Top)

r2 =

- (lr.Left - lr.Right)), lr.Top)

g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)

r1 =

+ (oWidth - lr.Right)), y, lr.Right, lr.Top)

r2 =

+ (r.Width - lr.Right)), y1, lr.Right, lr.Top)

g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)

r1 =

+ (oWidth - lr.Right)), (y + lr.Top), lr.Right, (obj.Height _

- (lr.Top - lr.Bottom)))

r2 =

+ (r.Width - lr.Right)), (y1 + lr.Top), lr.Right, (r.Height _

- (lr.Top - lr.Bottom)))

g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)

r1 =

+ (oWidth - lr.Right)), (y _

+ (obj.Height - lr.Bottom)), lr.Right, lr.Bottom)

r2 =

+ (r.Width - lr.Right)), (y1 _

+ (r.Height - lr.Bottom)), lr.Right, lr.Bottom)

g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)

r1 =

+ (obj.Height - lr.Bottom)), (oWidth _

- (lr.Left - lr.Right)), lr.Bottom)

r2 =

+ (r.Height - lr.Bottom)), (r.Width _

- (lr.Left - lr.Right)), lr.Bottom)

g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)

r1 =

- (lr.Left - lr.Right)), (obj.Height _

- (lr.Top - lr.Bottom)))

r2 =

- (lr.Left - lr.Right)), (r.Height _

- (lr.Top - lr.Bottom)))

g.DrawImage(obj, r2, r1, GraphicsUnit.Pixel)

<>

withinThis.X = (withinThis.X _

+ (withinThis.Width - alignThis.Width))

<>

withinThis.X = (withinThis.X _

+ (((withinThis.Width - alignThis.Width) _

+ 1) _

/ 2))

withinThis.Width = alignThis.Width

<>

withinThis.Y = (withinThis.Y _

+ (withinThis.Height - alignThis.Height))

<>

withinThis.Y = (withinThis.Y _

+ (((withinThis.Height - alignThis.Height) _

+ 1) _

/ 2))

withinThis.Height = alignThis.Height

How the result looks like, you can see in the attached screenshot on top of this article, or you could just download the code and execute the exe-file in the debugfolder to see the working example.

I hope this small piece of code can be useful to someone like the many good code examples I found at this site.

Regards,

Andy

Shared anyRight As ContentAlignment = (ContentAlignment.BottomRight _Or (ContentAlignment.MiddleRight Or ContentAlignment.TopRight))Public Shared anyTop As ContentAlignment = (ContentAlignment.TopRight _Or (ContentAlignment.TopCenter Or ContentAlignment.TopLeft))Public Shared anyBottom As ContentAlignment = (ContentAlignment.BottomRight _Or (ContentAlignment.BottomCenter Or ContentAlignment.BottomLeft))Public Shared anyCenter As ContentAlignment = (ContentAlignment.BottomCenter _Or (ContentAlignment.MiddleCenter Or ContentAlignment.TopCenter))Public Shared anyMiddle As ContentAlignment = (ContentAlignment.MiddleRight _Or (ContentAlignment.MiddleCenter Or ContentAlignment.MiddleLeft))Private Sub TekenAchtergrond(ByVal g As Graphics, ByVal obj As Image, ByVal r As Rectangle, ByVal index As Integer)If (obj Is Nothing) ThenReturnEnd IfDim oWidth As Integer = obj.WidthDim lr As Rectangle = Rectangle.FromLTRB(0, 0, 0, 0)Dim r2 As RectangleDim r1 As RectangleDim x As Integer = ((index - 1) _Dim y As Integer = 0Dim x1 As Integer = r.LeftDim y1 As Integer = r.TopIf ((r.Height > obj.Height) _AndAlso (r.Width <= oWidth)) ThenNew Rectangle(x, y, oWidth, lr.Top)New Rectangle(x1, y1, r.Width, lr.Top)New Rectangle(x, (y + lr.Top), oWidth, (obj.Height _New Rectangle(x1, (y1 + lr.Top), r.Width, (r.Height _If ((lr.Top + lr.Bottom) _ThenEnd IfNew Rectangle(x, (y _New Rectangle(x1, (y1 _ElseIf ((r.Height <= obj.Height) _AndAlso (r.Width > oWidth)) ThenNew Rectangle(x, y, lr.Left, obj.Height)New Rectangle(x1, y1, lr.Left, r.Height)New Rectangle((x + lr.Left), y, (oWidth _New Rectangle((x1 + lr.Left), y1, (r.Width _New Rectangle((x _New Rectangle((x1 _ElseIf ((r.Height <= obj.Height) _AndAlso (r.Width <= oWidth)) ThenNew Rectangle(((index - 1) _New Rectangle(x1, y1, r.Width, r.Height), r1, GraphicsUnit.Pixel)ElseIf ((r.Height > obj.Height) _AndAlso (r.Width > oWidth)) Then'top-leftNew Rectangle(x, y, lr.Left, lr.Top)New Rectangle(x1, y1, lr.Left, lr.Top)'top-bottomNew Rectangle(x, (y _New Rectangle(x1, (y1 _'leftNew Rectangle(x, (y + lr.Top), lr.Left, (obj.Height _New Rectangle(x1, (y1 + lr.Top), lr.Left, (r.Height _'topNew Rectangle((x + lr.Left), y, (oWidth _New Rectangle((x1 + lr.Left), y1, (r.Width _'right-topNew Rectangle((x _New Rectangle((x1 _'RightNew Rectangle((x _New Rectangle((x1 _'right-bottomNew Rectangle((x _New Rectangle((x1 _'bottomNew Rectangle((x + lr.Left), (y _New Rectangle((x1 + lr.Left), (y1 _'CenterNew Rectangle((x + lr.Left), (y + lr.Top), (oWidth _New Rectangle((x1 + lr.Left), (y1 + lr.Top), (r.Width _End IfEnd SubPrivate Function HAlignWithin(ByVal alignThis As Size, ByVal withinThis As Rectangle, ByVal align As ContentAlignment) As RectangleIf ((align And anyRight) _CType(0, ContentAlignment)) ThenElseIf ((align And anyCenter) _CType(0, ContentAlignment)) ThenEnd IfReturn withinThisEnd FunctionPrivate Function VAlignWithin(ByVal alignThis As Size, ByVal withinThis As Rectangle, ByVal align As ContentAlignment) As RectangleIf ((align And anyBottom) _CType(0, ContentAlignment)) ThenElseIf ((align And anyMiddle) _CType(0, ContentAlignment)) ThenEnd IfReturn withinThisEnd Function

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here