DataGridView column alignment header vs data

Andrew Mercer 486 Reputation points
2024-05-23T15:21:45.1333333+00:00

In the pic below, the DataGridView column header (Column1) is misaligned with the data cell text below it (XXX). The misalignment is nearly one character width. It is more visually obvious with a larger font. The pic comes from a minimal Forms app. The form has one DataGridView control and one text column. No properties were set, and there is no code in the app. It is just a form, a DataGridView control, and a single column. FYI I get the same result if I change the column's Default Cell Style, Layout, Alignment from NotSet to MiddleLeft.

I can't figure it out. I've been down many rabbit holes mostly from internet search hits on this question, and the suggestions seem misguided and lead nowhere. In this minimal app, my intuition says the columns should line up. FYI VS 2019, FW 4.8, and this is a VB Forms app.

User's image

Windows Forms
Windows Forms
A set of .NET Framework managed libraries for developing graphical user interfaces.
1,915 questions
.NET
.NET
Microsoft Technologies based on the .NET software framework.
4,012 questions
VB
VB
An object-oriented programming language developed by Microsoft that is implemented on the .NET Framework. Previously known as Visual Basic .NET.
2,760 questions
{count} votes

Accepted answer
  1. KOZ6.0 6,580 Reputation points
    2024-05-23T19:30:19.9133333+00:00

    The code is publicly available, so all you need to do is customize DataGridViewColumnHeaderCell to match the Paint of DataGridViewTextBoxCell.

    Public Class FitHeaderCell
    	Inherits DataGridViewColumnHeaderCell
    
    	Private Const DATAGRIDVIEWTEXTBOXCELL_ignoreNextMouseClick As Byte = 1
    	Private Const DATAGRIDVIEWTEXTBOXCELL_horizontalTextOffsetLeft As Byte = 3
    	Private Const DATAGRIDVIEWTEXTBOXCELL_horizontalTextOffsetRight As Byte = 4
    	Private Const DATAGRIDVIEWTEXTBOXCELL_horizontalTextMarginLeft As Byte = 0
    	Private Const DATAGRIDVIEWTEXTBOXCELL_horizontalTextMarginRight As Byte = 0
    	Private Const DATAGRIDVIEWTEXTBOXCELL_verticalTextOffsetTop As Byte = 2
    	Private Const DATAGRIDVIEWTEXTBOXCELL_verticalTextOffsetBottom As Byte = 1
    	Private Const DATAGRIDVIEWTEXTBOXCELL_verticalTextMarginTopWithWrapping As Byte = 1
    	Private Const DATAGRIDVIEWTEXTBOXCELL_verticalTextMarginTopWithoutWrapping As Byte = 2
    	Private Const DATAGRIDVIEWTEXTBOXCELL_verticalTextMarginBottom As Byte = 1
    
    	Protected Overrides Sub Paint(graphics As Graphics, clipBounds As Rectangle,
    									cellBounds As Rectangle, rowIndex As Integer,
    									dataGridViewElementState As DataGridViewElementStates,
    									value As Object, formattedValue As Object, errorText As String,
    									cellStyle As DataGridViewCellStyle, advancedBorderStyle As DataGridViewAdvancedBorderStyle,
    									paintParts As DataGridViewPaintParts)
    		Dim beforeParts = paintParts And (
    								DataGridViewPaintParts.Border Or
    								DataGridViewPaintParts.Background Or
    								DataGridViewPaintParts.ContentBackground Or
    								DataGridViewPaintParts.SelectionBackground)
    		Dim afterParts = paintParts And DataGridViewPaintParts.ErrorIcon
    
    		MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex,
    					 dataGridViewElementState, value, formattedValue,
    					 errorText, cellStyle, advancedBorderStyle, beforeParts)
    
    		If paintParts.HasFlag(DataGridViewPaintParts.ContentForeground) Then
    			Dim BorderWidths As Rectangle = MyBase.BorderWidths(advancedBorderStyle)
    			Dim valBounds As Rectangle = cellBounds
    			valBounds.Offset(BorderWidths.X, BorderWidths.Y)
    			valBounds.Width -= BorderWidths.Right
    			valBounds.Height -= BorderWidths.Bottom
    
    			If cellStyle.Padding <> Padding.Empty Then
    				If DataGridView.RightToLeft = RightToLeft.Yes Then
    					valBounds.Offset(cellStyle.Padding.Right, cellStyle.Padding.Top)
    				Else
    					valBounds.Offset(cellStyle.Padding.Left, cellStyle.Padding.Top)
    				End If
    				valBounds.Width -= cellStyle.Padding.Horizontal
    				valBounds.Height -= cellStyle.Padding.Vertical
    			End If
    
    			Dim verticalTextMarginTop = If(cellStyle.WrapMode = DataGridViewTriState.True, DATAGRIDVIEWTEXTBOXCELL_verticalTextMarginTopWithWrapping, DATAGRIDVIEWTEXTBOXCELL_verticalTextMarginTopWithoutWrapping)
    			valBounds.Offset(DATAGRIDVIEWTEXTBOXCELL_horizontalTextMarginLeft, verticalTextMarginTop)
    			valBounds.Width -= DATAGRIDVIEWTEXTBOXCELL_horizontalTextMarginLeft + DATAGRIDVIEWTEXTBOXCELL_horizontalTextMarginRight
    			valBounds.Height -= verticalTextMarginTop + DATAGRIDVIEWTEXTBOXCELL_verticalTextMarginBottom
    			valBounds.Width -= 1 ' adjust
    			If valBounds.Width > 0 AndAlso valBounds.Height > 0 Then
    				Dim flags As TextFormatFlags = ComputeTextFormatFlagsForCellStyleAlignment(DataGridView.RightToLeft = RightToLeft.Yes, cellStyle.Alignment, cellStyle.WrapMode)
    				If (flags And TextFormatFlags.SingleLine) <> 0 Then
    					flags = flags Or TextFormatFlags.EndEllipsis
    				End If
    				Dim formattedValueStr As String = TryCast(formattedValue, String)
    				TextRenderer.DrawText(graphics, formattedValueStr, cellStyle.Font, valBounds, cellStyle.ForeColor, flags)
    			End If
    		End If
    
    		MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex,
    					 dataGridViewElementState, value, formattedValue,
    					 errorText, cellStyle, advancedBorderStyle, afterParts)
    	End Sub
    
    	Friend Shared Function ComputeTextFormatFlagsForCellStyleAlignment(rightToLeft As Boolean, alignment As DataGridViewContentAlignment, wrapMode As DataGridViewTriState) As TextFormatFlags
    		Dim tff As TextFormatFlags
    		Select Case alignment
    			Case DataGridViewContentAlignment.TopLeft
    				tff = TextFormatFlags.Top
    				If rightToLeft Then
    					tff = tff Or TextFormatFlags.Right
    				Else
    					tff = tff Or TextFormatFlags.Left
    				End If
    				Exit Select
    			Case DataGridViewContentAlignment.TopCenter
    				tff = TextFormatFlags.Top Or TextFormatFlags.HorizontalCenter
    				Exit Select
    			Case DataGridViewContentAlignment.TopRight
    				tff = TextFormatFlags.Top
    				If rightToLeft Then
    					tff = tff Or TextFormatFlags.Left
    				Else
    					tff = tff Or TextFormatFlags.Right
    				End If
    				Exit Select
    			Case DataGridViewContentAlignment.MiddleLeft
    				tff = TextFormatFlags.VerticalCenter
    				If rightToLeft Then
    					tff = tff Or TextFormatFlags.Right
    				Else
    					tff = tff Or TextFormatFlags.Left
    				End If
    				Exit Select
    			Case DataGridViewContentAlignment.MiddleCenter
    				tff = TextFormatFlags.VerticalCenter Or TextFormatFlags.HorizontalCenter
    				Exit Select
    			Case DataGridViewContentAlignment.MiddleRight
    				tff = TextFormatFlags.VerticalCenter
    				If rightToLeft Then
    					tff = tff Or TextFormatFlags.Left
    				Else
    					tff = tff Or TextFormatFlags.Right
    				End If
    				Exit Select
    			Case DataGridViewContentAlignment.BottomLeft
    				tff = TextFormatFlags.Bottom
    				If rightToLeft Then
    					tff = tff Or TextFormatFlags.Right
    				Else
    					tff = tff Or TextFormatFlags.Left
    				End If
    				Exit Select
    			Case DataGridViewContentAlignment.BottomCenter
    				tff = TextFormatFlags.Bottom Or TextFormatFlags.HorizontalCenter
    				Exit Select
    			Case DataGridViewContentAlignment.BottomRight
    				tff = TextFormatFlags.Bottom
    				If rightToLeft Then
    					tff = tff Or TextFormatFlags.Left
    				Else
    					tff = tff Or TextFormatFlags.Right
    				End If
    				Exit Select
    			Case Else
    				tff = TextFormatFlags.HorizontalCenter Or TextFormatFlags.VerticalCenter
    				Exit Select
    		End Select
    		If wrapMode = DataGridViewTriState.[False] Then
    			tff = tff Or TextFormatFlags.SingleLine
    		Else
    			tff = tff Or TextFormatFlags.WordBreak
    		End If
    		tff = tff Or TextFormatFlags.NoPrefix
    		tff = tff Or TextFormatFlags.PreserveGraphicsClipping
    		If rightToLeft Then
    			tff = tff Or TextFormatFlags.RightToLeft
    		End If
    		Return tff
    	End Function
    
    End Class
    

    How to use:

        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            DataGridView1.Columns(0).HeaderCell = New FitHeaderCell
        End Sub
    

    The customized left column is aligned.

    enter image description here

    1 person found this answer helpful.

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.