none
Hot oto add a Buttom to a DatagridView Column Header RRS feed

  • Question

  • HI,

    I would like to add a small buttom inside a datagridview column header

    Both  dgv and columns can be resized and columns can be deleted.

    Haw to do that ?

    Friday, March 2, 2018 1:00 PM

Answers

  • Hi

    Here is some code that resizes and locates a Button4 to the header cell of Column3 of DataGridView1. Button4 has been added via the Designer. To allow for resize, put the code in the Form1.Resize event handler. This then needs a boolean variable to indicate that the Form controls have been initialized.

        ' in FormShown event handler
        started = True
      End Sub

      Dim started As Boolean = False
      Private Sub Form1_Resize(sender As Object, e As EventArgs) Handles MyBase.Resize
        If Not started Then Exit Sub
        Dim r As Rectangle = DataGridView1.GetCellDisplayRectangle(3, -1, False)
        Button4.Size = r.Size
        Button4.Location = r.Location
      End Sub


    Regards Les, Livingston, Scotland



    • Edited by leshay Friday, March 2, 2018 1:47 PM altered code for Resize
    • Marked as answer by Claudio111 Saturday, March 3, 2018 10:45 AM
    Friday, March 2, 2018 1:38 PM

All replies

  • Hi

    Here is some code that resizes and locates a Button4 to the header cell of Column3 of DataGridView1. Button4 has been added via the Designer. To allow for resize, put the code in the Form1.Resize event handler. This then needs a boolean variable to indicate that the Form controls have been initialized.

        ' in FormShown event handler
        started = True
      End Sub

      Dim started As Boolean = False
      Private Sub Form1_Resize(sender As Object, e As EventArgs) Handles MyBase.Resize
        If Not started Then Exit Sub
        Dim r As Rectangle = DataGridView1.GetCellDisplayRectangle(3, -1, False)
        Button4.Size = r.Size
        Button4.Location = r.Location
      End Sub


    Regards Les, Livingston, Scotland



    • Edited by leshay Friday, March 2, 2018 1:47 PM altered code for Resize
    • Marked as answer by Claudio111 Saturday, March 3, 2018 10:45 AM
    Friday, March 2, 2018 1:38 PM
  • The main problem here is keeping the button in place when the column header moves, particularly with horizontal scrolling in the data grid view.

    My post in the other thread (https://social.msdn.microsoft.com/Forums/en-US/01f0b149-1bdb-48c4-b7aa-273e874d92a2/how-to-anchor-a-button-to-datagridview-column-header?forum=vbgeneral#a776a67a-a37b-41c2-8a9d-b52782f79be1) contains an example of creating a custom header cell with a button in it, but as that thread is getting long, I'll add the same code here for anyone who finds this thread via a search.

    Public Class DataGridViewButtonHeaderCell
        Inherits DataGridViewColumnHeaderCell
    
        Public Event HeaderButtonClick As EventHandler
    
        ' button size will be column height minus this amount, square
        Public Property ButtonOffset As Integer = 2
    
        Private buttonBounds As Rectangle 'store button bounds
        Private isMouseDown As Boolean 'track mouse down over button for drawing button state
        Private lastSize As Size 'track column size to ignore size changes
        Private sortDirection As ComponentModel.ListSortDirection 'track sort direction for displaying sort gylph
    
        ' helper method to determine if button is clicked
        Private Function IsPointInButtonBounds(value As Point, columnIndex As Integer) As Boolean
            Return buttonBounds.Contains(value + Me.DataGridView.GetColumnDisplayRectangle(columnIndex, True).Location - New Point(Me.DataGridView.HorizontalScrollingOffset, 0))
        End Function
    
        Protected Overrides Sub OnDataGridViewChanged()
            MyBase.OnDataGridViewChanged()
            ' need to programmaticaly control sorting so that clicking the button doesn't cause a sort
            If Me.DataGridView IsNot Nothing Then
                Me.DataGridView.Columns.Item(Me.ColumnIndex).SortMode = DataGridViewColumnSortMode.Programmatic
                AddHandler Me.DataGridView.Sorted, Sub(sender As Object, e As EventArgs)
                                                       If sender Is Me.DataGridView Then
                                                           If Me.DataGridView.SortedColumn IsNot Me.DataGridView.Columns.Item(Me.ColumnIndex) Then
                                                               Me.SortGlyphDirection = SortOrder.None
                                                           End If
                                                       End If
                                                   End Sub
                lastSize = Me.Size
            End If
        End Sub
    
        ' provide an event to handle for the custom button click
        Protected Overridable Sub OnHeaderButtonClick(e As EventArgs)
            RaiseEvent HeaderButtonClick(Me, e)
        End Sub
    
        ' determine if button is being clicked and redraw cell
        Protected Overrides Sub OnMouseDown(e As DataGridViewCellMouseEventArgs)
            MyBase.OnMouseDown(e)
            isMouseDown = IsPointInButtonBounds(e.Location, e.ColumnIndex)
            Me.DataGridView.InvalidateCell(Me)
        End Sub
    
        Protected Overrides Sub OnMouseUp(e As DataGridViewCellMouseEventArgs)
            MyBase.OnMouseUp(e)
            If Size = lastSize Then 'ignore column size changes
                ' if button is being clicked, raise the click event
                If IsPointInButtonBounds(e.Location, e.ColumnIndex) Then
                    OnHeaderButtonClick(EventArgs.Empty)
                Else
                    ' otherwise sort the column
                    Dim column = Me.DataGridView.Columns.Item(e.ColumnIndex)
                    Dim direction As ComponentModel.ListSortDirection = System.ComponentModel.ListSortDirection.Ascending
                    If Me.DataGridView.SortedColumn Is column Then direction = If(sortDirection = System.ComponentModel.ListSortDirection.Ascending, ComponentModel.ListSortDirection.Descending, ComponentModel.ListSortDirection.Ascending)
                    Me.DataGridView.Sort(column, direction)
                    Me.SortGlyphDirection = If(direction = System.ComponentModel.ListSortDirection.Ascending, SortOrder.Ascending, SortOrder.Descending)
                    sortDirection = direction
                End If
            End If
    
            isMouseDown = False
            Me.DataGridView.InvalidateCell(Me)
        End Sub
    
        Protected Overrides Sub Paint(graphics As Graphics, clipBounds As Rectangle, cellBounds As Rectangle, rowIndex As Integer, elementState As DataGridViewElementStates, value As Object, formattedValue As Object, errorText As String, cellStyle As DataGridViewCellStyle, advancedBorderStyle As DataGridViewAdvancedBorderStyle, paintParts As DataGridViewPaintParts)
            ' store the current button size
            lastSize = Size
    
            ' calculate the button bounds
            buttonBounds = New Rectangle(cellBounds.Right - cellBounds.Height, cellBounds.Top + ButtonOffset, cellBounds.Height - ButtonOffset * 2, cellBounds.Height - ButtonOffset * 2)
    
            ' paint background and border to erase previous contents
            MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, DataGridViewPaintParts.Background Or DataGridViewPaintParts.Border)
    
            ' paint custom button
            ControlPaint.DrawButton(graphics, buttonBounds, If(isMouseDown, ButtonState.Pushed, ButtonState.Normal))
            'TODO: draw something in the button if desired
    
            'resize cell to exclude button area
            cellBounds.Width -= buttonBounds.Width + ButtonOffset
            'perform default painting of the header cell within the modified bounds
            MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts)
        End Sub
    End Class

    Example of using the custom header cell:

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ' choose a column
        Dim column = DataGridView1.Columns.Item(0)
        ' create a new custom button header cell
        Dim headerCell As New DataGridViewButtonHeaderCell
        ' handle the custom button's click event
        AddHandler headerCell.HeaderButtonClick, Sub(_sender As Object, _e As EventArgs)
                                                     ' do something when the button is clicked
                                                     MessageBox.Show("button clicked")
                                                 End Sub
        ' set the custom header cell as the column header
        column.HeaderCell = headerCell
    
        If Not IO.Directory.Exists(filePath) Then IO.Directory.CreateDirectory(filePath)
    End Sub
    

    Screen shot:


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Saturday, March 3, 2018 7:43 PM
    Moderator