Click here to Skip to main content
15,888,113 members
Articles / Desktop Programming / Windows Forms
Article

CheckBox Header Column For DataGridView

Rate me:
Please Sign up or sign in to vote.
4.85/5 (33 votes)
23 Aug 20071 min read 292.4K   95   47
Presenting a solution for having CheckBox control in the header of DataGridView

Introduction

This article will show you how to create CheckBoxHeaderColumn for DataGridView. It will expose CheckBoxClicked event which you can consume in your client application.

Background

It is very common to have a list of items in DataGridView with a check box in the first column where your later action will depend on user selection. This can be very easily done by having a first column defined as DataGridViewCheckBoxCell object. But, how can your customer select all items in the list (let's say you are working on an email client app and the user wants to delete all of his 100 spams). This was the main idea to generate a class which will have a check box item in the header where the developer can have full control after the user checks/unchecks an item in the header. A common action is to check/uncheck all items in the DataGridView depending on whether the header is checked/unchecked.

Using the Code

The whole solution (control) is very simple and contains just one class DataGridViewCheckBoxHeaderCell.

On the client side, the developer just needs to define DataGridViewCheckBoxColumn and assign DataGridCheckBoxHeaderCell as a HeaderCell. Here is the code to do that:

C#
DataGridViewCheckBoxColumn colCB = new DataGridViewCheckBoxColumn();
DatagridViewCheckBoxHeaderCell cbHeader = new DatagridViewCheckBoxHeaderCell();
colCB.HeaderCell = cbHeader;
datagridview1.Columns.Add(colCB);

As mentioned before, always user clicks on a Checkbox in the header object will fire CheckboxClicked event which you can consume in your application:

C#
cbHeader.OnCheckBoxClicked += 
    new CheckBoxClickedHandler(cbHeader_OnCheckBoxClicked);

In the function cbHeader_OnCheckBoxClicked(), you can check/uncheck all of DataGridView rows or do any other action.

And here is a control source:

C#
namespace TestRef
{   
    public delegate void CheckBoxClickedHandler(bool state);
    public class DataGridViewCheckBoxHeaderCellEventArgs : EventArgs
    {
        bool _bChecked;
        public DataGridViewCheckBoxHeaderCellEventArgs(bool bChecked)
        {
            _bChecked = bChecked;
        }
        public bool Checked
        {
            get { return _bChecked; }
        }
    }
    class DatagridViewCheckBoxHeaderCell : DataGridViewColumnHeaderCell
    {
        Point checkBoxLocation;
        Size checkBoxSize;
        bool _checked = false;
        Point _cellLocation = new Point();
        System.Windows.Forms.VisualStyles.CheckBoxState _cbState = 
            System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal;
        public event CheckBoxClickedHandler OnCheckBoxClicked;
 
        public DatagridViewCheckBoxHeaderCell()
        {           
        }

        protected override void Paint(System.Drawing.Graphics graphics, 
            System.Drawing.Rectangle clipBounds, 
            System.Drawing.Rectangle cellBounds, 
            int rowIndex, 
            DataGridViewElementStates dataGridViewElementState, 
            object value, 
            object formattedValue, 
            string errorText, 
            DataGridViewCellStyle cellStyle, 
            DataGridViewAdvancedBorderStyle advancedBorderStyle, 
            DataGridViewPaintParts paintParts)
        {
            base.Paint(graphics, clipBounds, cellBounds, rowIndex, 
                dataGridViewElementState, value, 
                formattedValue, errorText, cellStyle, 
                advancedBorderStyle, paintParts);
            Point p = new Point();
            Size s = CheckBoxRenderer.GetGlyphSize(graphics, 
            System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal);
            p.X = cellBounds.Location.X + 
                (cellBounds.Width / 2) - (s.Width / 2) ;
            p.Y = cellBounds.Location.Y + 
                (cellBounds.Height / 2) - (s.Height / 2);
            _cellLocation = cellBounds.Location;
            checkBoxLocation = p;
            checkBoxSize = s;
            if (_checked)
                _cbState = System.Windows.Forms.VisualStyles.
                    CheckBoxState.CheckedNormal;
            else
                _cbState = System.Windows.Forms.VisualStyles.
                    CheckBoxState.UncheckedNormal;
            CheckBoxRenderer.DrawCheckBox
            (graphics, checkBoxLocation, _cbState);
        }

        protected override void OnMouseClick(DataGridViewCellMouseEventArgs e)
        {
            Point p = new Point(e.X + _cellLocation.X, e.Y + _cellLocation.Y);
            if (p.X >= checkBoxLocation.X && p.X <= 
                checkBoxLocation.X + checkBoxSize.Width 
            && p.Y >= checkBoxLocation.Y && p.Y <= 
                checkBoxLocation.Y + checkBoxSize.Height)
            {
                _checked = !_checked;
                if (OnCheckBoxClicked != null)
                {
                    OnCheckBoxClicked(_checked);
                    this.DataGridView.InvalidateCell(this);
                }
                
            } 
            base.OnMouseClick(e);
        }     
    }
}

I hope you will find this article helpful while this is a solution used in our cross database comparison tool for selecting rows for synchronization between databases. Besides this, you can easily extend and fully customize painting of the CheckBox control, introduce tri state CheckBoxes and do many others as with the normal CheckBox.

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


Written By
Software Developer (Senior)
Austria Austria
Working as a .NET and database developer

Comments and Discussions

 
GeneralMy vote of 5 Pin
evry1falls14-Apr-24 16:47
evry1falls14-Apr-24 16:47 
QuestionText Alignment in Header Pin
Member 1575871719-Sep-22 0:52
Member 1575871719-Sep-22 0:52 
BugFirst Row is not getting updated. Pin
sejaltanna28-May-17 23:51
sejaltanna28-May-17 23:51 
QuestionUncheck box when a button is selected Pin
Member 1302199324-Feb-17 6:59
Member 1302199324-Feb-17 6:59 
QuestionTo the Author - Usage of this piece of code for Official purposes Pin
SharathNS4-Apr-16 21:57
SharathNS4-Apr-16 21:57 
SuggestionMy vote of 5 Pin
Kyaw Zin Soe13-Dec-15 23:11
Kyaw Zin Soe13-Dec-15 23:11 
QuestionUse Pin
aramosvizcarra28-Aug-14 3:26
aramosvizcarra28-Aug-14 3:26 
AnswerRe: Use Pin
DLM@TD25-Sep-14 8:14
DLM@TD25-Sep-14 8:14 
SuggestionVersion based on CheckBoxState: unchecked, checked, mixed and normal, hot, pressed Pin
dethtroll27-Jan-12 5:16
dethtroll27-Jan-12 5:16 
Questiona vb.net version Pin
jtxd30-Dec-11 15:32
jtxd30-Dec-11 15:32 
I've translated the code to vb.net version, and made some improvment.
First I add a default handler to check all the checkbox belongs to the column, and add a 'Handled' property to the eventargs to control whether the action would do or not...

VB
#Region "Imports"
 Imports System.Drawing
Imports System.Windows.Forms
Imports System.Windows.Forms.VisualStyles
Imports System.ComponentModel

#End Region

Public Class DataGridViewColumnHeaderCheckBoxCell
    Inherits DataGridViewColumnHeaderCell

#Region "Fields"
     Private _Checked As Boolean
    Private _CheckBoxSize As Size
    Private _CheckBoxLocation As Point
    Private _CheckBoxBounds As Rectangle
    Private _CellLocation As New Point()
    Private _CheckBoxAlignment As HorizontalAlignment = HorizontalAlignment.Center

#End Region

#Region "Events"
     Public Event CheckBoxCheckedChanged As DataGridViewCheckBoxHeaderCellEvenHandler

#End Region

#Region "Constructor"
     Public Sub New()
        MyBase.New()
    End Sub

#End Region

#Region "Properties"
     Public Property CheckBoxAlignment() As HorizontalAlignment
        Get
            Return _CheckBoxAlignment
        End Get
        Set(ByVal value As HorizontalAlignment)
            If Not [Enum].IsDefined(GetType(HorizontalAlignment), value) Then

                Throw New InvalidEnumArgumentException("value", CInt(value), GetType(HorizontalAlignment))
            End If
            If _CheckBoxAlignment <> value Then
                _CheckBoxAlignment = value
                If Me.DataGridView IsNot Nothing Then
                    Me.DataGridView.InvalidateCell(Me)
                End If
            End If
        End Set
    End Property

    Public Property Checked() As Boolean
        Get
            Return _Checked
        End Get
        Set(ByVal value As Boolean)
            If _Checked <> value Then
                _Checked = value
                If Me.DataGridView IsNot Nothing Then
                    'raise event
                    RaiseCheckBoxCheckedChanged()

                    Me.DataGridView.InvalidateCell(Me)
                End If
            End If
        End Set
    End Property

#End Region

#Region "Methods"
     Protected Overridable Sub OnCheckBoxCheckedChanged(ByVal e As DataGridViewCheckBoxHeaderCellEventArgs)
        RaiseEvent CheckBoxCheckedChanged(Me, e)
    End Sub

#End Region

#Region "Override"
     Protected Overrides Sub Paint(ByVal graphics As Graphics, ByVal clipBounds As Rectangle, ByVal cellBounds As Rectangle, ByVal rowIndex As Integer, ByVal dataGridViewElementState As DataGridViewElementStates, ByVal value As Object, _
            ByVal formattedValue As Object, ByVal errorText As String, ByVal cellStyle As DataGridViewCellStyle, ByVal advancedBorderStyle As DataGridViewAdvancedBorderStyle, ByVal paintParts As DataGridViewPaintParts)
        'checkbox bounds
        Dim state As CheckBoxState = Me.CheckBoxState
        _CellLocation = cellBounds.Location
        _CheckBoxSize = CheckBoxRenderer.GetGlyphSize(graphics, state)
        Dim p As New Point()
        p.Y = cellBounds.Location.Y + (cellBounds.Height / 2) - (_CheckBoxSize.Height / 2)
        Select Case _CheckBoxAlignment
            Case HorizontalAlignment.Center
                p.X = cellBounds.Location.X + (cellBounds.Width / 2) - (_CheckBoxSize.Width / 2) - 1
                Exit Select
            Case HorizontalAlignment.Left
                p.X = cellBounds.Location.X + 2
                Exit Select
            Case HorizontalAlignment.Right
                p.X = cellBounds.Right - _CheckBoxSize.Width - 4
                Exit Select
        End Select
        _CheckBoxLocation = p
        _CheckBoxBounds = New Rectangle(_CheckBoxLocation, _CheckBoxSize)

        'paint background
        paintParts = paintParts And Not DataGridViewPaintParts.ContentForeground
        MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, dataGridViewElementState, value, _
         formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts)

        'paint foreground
        Select Case _CheckBoxAlignment
            Case HorizontalAlignment.Center
                cellBounds.Width = _CheckBoxLocation.X - cellBounds.X - 2
                Exit Select
            Case HorizontalAlignment.Left
                cellBounds.X += _CheckBoxSize.Width + 2
                cellBounds.Width -= _CheckBoxSize.Width + 2
                Exit Select
            Case HorizontalAlignment.Right
                cellBounds.Width -= _CheckBoxSize.Width + 4
                Exit Select
        End Select
        paintParts = DataGridViewPaintParts.ContentForeground
        MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, dataGridViewElementState, value, _
         formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts)

        'paint check box           
        CheckBoxRenderer.DrawCheckBox(graphics, _CheckBoxLocation, state)
    End Sub

    Protected Overrides Sub OnMouseClick(ByVal e As DataGridViewCellMouseEventArgs)
        If e.Button = MouseButtons.Left Then
            If Not Me.OwningColumn.ReadOnly Then
                'click on check box ?
                Dim p As New Point(_CellLocation.X + e.X, _CellLocation.Y + e.Y)
                If _CheckBoxBounds.Contains(p) Then
                    'raise event
                    RaiseCheckBoxCheckedChanged()
                End If
            End If
        End If
        MyBase.OnMouseClick(e)
    End Sub

    Protected Overrides Sub OnKeyDown(ByVal e As KeyEventArgs, ByVal rowIndex As Integer)
        If e.KeyCode = Keys.Space Then
            If Not Me.OwningColumn.ReadOnly Then
                'raise event
                RaiseCheckBoxCheckedChanged()
            End If
        End If
        MyBase.OnKeyDown(e, rowIndex)
    End Sub

    Public Overrides Function Clone() As Object
        Dim cell As DataGridViewColumnHeaderCheckBoxCell = TryCast(MyBase.Clone(), DataGridViewColumnHeaderCheckBoxCell)
        If cell IsNot Nothing Then
            cell.Checked = Me.Checked
        End If
        Return cell
    End Function

#End Region

#Region "Private"
     Private Sub RaiseCheckBoxCheckedChanged()
        'raise event
        Dim e As New DataGridViewCheckBoxHeaderCellEventArgs(Not _Checked)
        Me.OnCheckBoxCheckedChanged(e)
        If Not e.Cancel Then
            Me._Checked = e.Checked
            Me.DataGridView.InvalidateCell(Me)

            If Not e.Handled Then
                Me.SetColumnCheckBoxChecked(e.Checked)
            End If
        End If
    End Sub

    Private Sub SetColumnCheckBoxChecked(ByVal checked As Boolean)
        For Each dgvr As DataGridViewRow In Me.DataGridView.Rows
            If (dgvr.IsNewRow) Then
                Continue For
            End If

            dgvr.Cells(Me.OwningColumn.Index).Value = checked
        Next

        Dim currCell As DataGridViewCell = Me.DataGridView.CurrentCell
        If (currCell IsNot Nothing AndAlso currCell.ColumnIndex = Me.OwningColumn.Index) Then
            Me.DataGridView.RefreshEdit()
        End If
    End Sub

    Private ReadOnly Property CheckBoxState() As CheckBoxState
        Get
            Dim enabled As Boolean = True
            If MyBase.DataGridView IsNot Nothing AndAlso Not MyBase.DataGridView.Enabled Then
                enabled = False
            End If
            If enabled Then
                Return IIf((_Checked), CheckBoxState.CheckedNormal, CheckBoxState.UncheckedNormal)
            End If
            Return IIf((_Checked), CheckBoxState.CheckedDisabled, CheckBoxState.UncheckedDisabled)
        End Get
    End Property

#End Region

End Class

#Region "Events and Delegates"
 Public Delegate Sub DataGridViewCheckBoxHeaderCellEvenHandler(ByVal sender As Object, ByVal e As DataGridViewCheckBoxHeaderCellEventArgs)

Public Class DataGridViewCheckBoxHeaderCellEventArgs
    Inherits CancelEventArgs

    Private _Checked As Boolean = False
    Private _Handled As Boolean = False

    Public Sub New(ByVal checkedValue As Boolean)
        MyBase.New()
        _Checked = checkedValue
    End Sub

    Public Sub New(ByVal checkedValue As Boolean, ByVal cancel As Boolean)
        MyBase.New(cancel)
        _Checked = checkedValue
    End Sub

    Public Sub New(ByVal checkedValue As Boolean, ByVal handled As Boolean, ByVal cancel As Boolean)
        MyBase.New(cancel)
        _Checked = checkedValue
        _Handled = handled
    End Sub

    Public ReadOnly Property Checked() As Boolean
        Get
            Return _Checked
        End Get
    End Property

    Public Property Handled() As Boolean
        Get
            Return _Handled
        End Get
        Set(ByVal value As Boolean)
            _Handled = value
        End Set
    End Property

End Class

#End Region

AnswerRe: a vb.net version Pin
Brent Murphy11-Jan-12 3:27
Brent Murphy11-Jan-12 3:27 
GeneralRe: a vb.net version Pin
tallion18-Nov-12 13:33
tallion18-Nov-12 13:33 
AnswerRe: a vb.net version Pin
evry1falls14-Apr-24 15:57
evry1falls14-Apr-24 15:57 
QuestionSetting 'DataPropertyName' stopped the OnCheckBoxClicked event firing Pin
trevormcalister17-Aug-11 4:31
trevormcalister17-Aug-11 4:31 
AnswerRe: Setting 'DataPropertyName' stopped the OnCheckBoxClicked event firing Pin
mohammad forutan31-Jul-12 21:15
mohammad forutan31-Jul-12 21:15 
GeneralThanks Pin
YZK30-Mar-11 0:03
YZK30-Mar-11 0:03 
GeneralMy vote of 5 Pin
JunfengGuo9-Mar-11 12:26
JunfengGuo9-Mar-11 12:26 
AnswerEven much simpler and a way to remove checkbox in an individual cell of in an CheckboxColumn Pin
loibl24-Mar-09 5:53
loibl24-Mar-09 5:53 
GeneralRe: Even much simpler and a way to remove checkbox in an individual cell of in an CheckboxColumn Pin
Christian Snook5-Nov-14 5:02
Christian Snook5-Nov-14 5:02 
QuestionHow to uncheck the header check box when user click on the grid cell and uncheck any of the check box Pin
ravikrmishra10-Feb-09 22:20
ravikrmishra10-Feb-09 22:20 
AnswerRe: Solution: to uncheck the header check box when user click on the grid cell and uncheck any of the check box Pin
Viji Raj1-Jul-09 10:30
Viji Raj1-Jul-09 10:30 
GeneralRe: Solution: to uncheck the header check box when user click on the grid cell and uncheck any of the check box Pin
Marpri22-Mar-12 0:55
Marpri22-Mar-12 0:55 
GeneralRe: Solution: to uncheck the header check box when user click on the grid cell and uncheck any of the check box Pin
mdimran2477-Jan-16 2:28
mdimran2477-Jan-16 2:28 
GeneralAppend check box after a column label Pin
TuttiFiesta30-Jan-09 3:48
TuttiFiesta30-Jan-09 3:48 
GeneralRe: Append check box after a column label Pin
TuttiFiesta30-Jan-09 4:23
TuttiFiesta30-Jan-09 4:23 

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.