Adding CheckBox to the Group header

17 posts, 0 answers
  1. Me
    Me avatar
    1 posts
    Member since:
    May 2011

    Posted 22 Jun 2011 Link to this post

    I need to add Checkbox to group header.
     i was able to do so, altering the code from 
    http://www.telerik.com/community/forums/winforms/gridview/adding-controls-to-the-group-header.aspx
    just needed to inherit from GridGroupContentCellElement class.
    but, the checkbox is appearing on the right most side and also i cannot attach to its check state toggle event.

    Thank you in advance for your help 


    the code for the inerited class is

     

    public class CustomGroupHeaderCell : GridGroupContentCellElement
        {
            public event EventHandler MeCheckChanged;
      
            private RadCheckBoxElement checkbox;
      
            public CustomGroupHeaderCell(GridViewColumn column, GridRowElement row)
                : base(column, row)
            { }
      
            protected override void CreateChildElements()
            {
                base.CreateChildElements();
                checkbox = new RadCheckBoxElement();
                checkbox.MinSize = new System.Drawing.Size(5, 5);
                checkbox.ToggleStateChanged += new StateChangedEventHandler(checkbox_ToggleStateChanged);
                Children.Insert(0,checkbox);
                ApplyThemeToElement(checkbox, "Bruder");  
            }
      
            private void checkbox_ToggleStateChanged(object sender, StateChangedEventArgs args)
            {
                if (MeCheckChanged != null)
                    MeCheckChanged(this, null);
            }
            protected override System.Drawing.SizeF ArrangeOverride(System.Drawing.SizeF finalSize)
            {
                SizeF size = base.ArrangeOverride(finalSize);
                RectangleF rect = GetClientRectangle(finalSize);
                if (this.checkbox != null)
                    this.checkbox.Arrange(new RectangleF(rect.Right - this.checkbox.DesiredSize.Width - 5,
                                                         rect.Top + (rect.Height - this.checkbox.DesiredSize.Height) / 2,
                                                         this.checkbox.DesiredSize.Width,
                                                         this.checkbox.DesiredSize.Height));
      
                return size;
            }
      
            private void ApplyThemeToElement(RadItem item, string themeName)
            {
                try
                {
                    if (item.ElementTree == null) return;
      
                    DefaultStyleBuilder builder = ThemeResolutionService.GetStyleSheetBuilder(
                                                 (RadControl)item.ElementTree.Control,
                                                  item.GetThemeEffectiveType().FullName,
                                                  string.Empty, themeName) as DefaultStyleBuilder;
      
                    if (builder != null)
                        item.Style = builder.Style;
                }
                catch (Exception ex)
                { }
            }
        }
                
      
            
      
    }
  2. Alexander
    Admin
    Alexander avatar
    306 posts

    Posted 27 Jun 2011 Link to this post

    Hello Me Moyb,

    The ArrangeOverride method of your custom cell defines the location of the checkbox in the cell. The implementation you have aligns it right. You can position it in the center of the cell using the following implementation of ArrangeOverride:
    protected override System.Drawing.SizeF ArrangeOverride(System.Drawing.SizeF finalSize)
    {
        SizeF size = base.ArrangeOverride(finalSize);
        RectangleF rect = GetClientRectangle(finalSize);
        if (this.checkbox != null)
        {
            this.checkbox.Arrange(new RectangleF(rect.Width / 2 - this.checkbox.DesiredSize.Width / 2,
                                                 rect.Top + (rect.Height - this.checkbox.DesiredSize.Height) / 2,
                                                 this.checkbox.DesiredSize.Width,
                                                 this.checkbox.DesiredSize.Height));
        }
     
        return size;
    }

    You can attach to your custom cell events after initializing the cell in the CreateCell event of RadGridView:
    private void radGridView1_CreateCell(object sender, GridViewCreateCellEventArgs e)
    {
        if (e.CellType == typeof(GridGroupContentCellElement))
        {
            CustomGroupHeaderCell customCell = new CustomGroupHeaderCell(e.Column, e.Row);
            customCell.MeCheckChanged += new EventHandler(customCell_MeCheckChanged);
            e.CellElement = customCell;
        }
    }
     
    private void customCell_MeCheckChanged(object sender, EventArgs e)
    {
    }

    I hope it helps you to accomplish your scenario.

    Best regards,
    Alexander
    the Telerik team
    Q1’11 SP1 of RadControls for WinForms is available for download; also available is the Q2'11 Roadmap for Telerik Windows Forms controls.
  3. UI for WinForms is Visual Studio 2017 Ready
  4. aquariens
    aquariens avatar
    8 posts
    Member since:
    Jun 2009

    Posted 14 Jul 2011 Link to this post

    Hi,

    I am having a problem implementing this solution (Attached snapshot)

    First, thanks for sharing the useful information, i tweaked the code a little bit to fit in my requirements. Everything is going well, when i check the checkBox in groupRow its checking all the rows in the group (fine), but when i scroll my gridview the checkBox in that specific groupRow losses its checked state and the check comes to some other groupRow (Randomly), Moreover it actually doesn't trigger "checkbox_ToggleStateChanged" with this.

    Blow is the code, please guide if i am doing something wrong?

    Class:

    Imports Telerik.WinControls.UI
    Imports Telerik.WinControls
     
    Public Class CustomGroupHeaderCell
        Inherits GridGroupContentCellElement
        Public Event MeCheckChanged As EventHandler
        Public Event MeKeyUp As EventHandler
     
        Private checkbox As RadCheckBoxElement
        Private textbox As RadTextBoxElement
     
        Public Sub New(ByVal column As GridViewColumn, ByVal row As GridRowElement)
            MyBase.New(column, row)
        End Sub
     
        Protected Overrides Sub CreateChildElements()
            MyBase.CreateChildElements()
            checkbox = New RadCheckBoxElement()
     
            checkbox.MinSize = New System.Drawing.Size(5, 5)
            'checkbox.Text = "Group)"
            AddHandler checkbox.ToggleStateChanged, AddressOf checkbox_ToggleStateChanged
            Children.Insert(0, checkbox)
            ApplyThemeToElement(checkbox, "Bruder")
     
            textbox = New RadTextBoxElement()
            AddHandler textbox.KeyUp, AddressOf textbox_keypress
     
            Children.Insert(0, textbox)
     
        End Sub
     
        Private Sub textbox_keypress(ByVal sender As Object, ByVal args As KeyEventArgs)
            If args.KeyCode = Keys.Enter Then
                pvGroupRowHeaderTextBoxValue = textbox.Text
                RaiseEvent MeKeyUp(Me, New KeyEventArgs(Keys.Enter))
     
            End If
     
        End Sub
     
        Private Sub checkbox_ToggleStateChanged(ByVal sender As Object, ByVal args As StateChangedEventArgs)
            RaiseEvent MeCheckChanged(Me, New StateChangedEventArgs(checkbox.ToggleState))
        End Sub
        Protected Overloads Overrides Function ArrangeOverride(ByVal finalSize As SizeF) As SizeF
            Dim size As SizeF = MyBase.ArrangeOverride(finalSize)
            Dim rect As RectangleF = GetClientRectangle(finalSize)
            If Me.checkbox IsNot Nothing Then
                Me.checkbox.Arrange(New RectangleF((finalSize.Width - Me.checkbox.DesiredSize.Width) / 1.18, (rect.Height - 20) / 2, 20, 20))
            End If
     
            If Me.textbox IsNot Nothing Then
                Me.textbox.Arrange(New RectangleF((finalSize.Width - Me.textbox.DesiredSize.Width) / 1.1, (rect.Height - 20) / 2, 40, 20))
            End If
            Return size
        End Function
     
        Private Sub ApplyThemeToElement(ByVal item As RadItem, ByVal themeName As String)
            Try
                If item.ElementTree Is Nothing Then
                    Return
                End If
     
                Dim builder As DefaultStyleBuilder = TryCast(ThemeResolutionService.GetStyleSheetBuilder(DirectCast(item.ElementTree.Control, RadControl), item.GetThemeEffectiveType().FullName, String.Empty, themeName), DefaultStyleBuilder)
     
                If builder IsNot Nothing Then
                    item.Style = builder.Style
                End If
            Catch ex As Exception
            End Try
        End Sub
    End Class

    Form:

    Private Sub radGridView1_CreateCell(ByVal sender As Object, ByVal e As GridViewCreateCellEventArgs) Handles grdData.CreateCell
        If e.CellType = GetType(GridGroupContentCellElement) Then
            Dim customCell As New CustomGroupHeaderCell(e.Column, e.Row)
            AddHandler customCell.MeCheckChanged, AddressOf customCell_MeCheckChanged
            AddHandler customCell.MeKeyUp, AddressOf customCell_MeKeyUp
            e.CellElement = customCell
        End If
    End Sub
     
    Private Sub customCell_MeKeyUp(ByVal sender As Object, ByVal e As KeyEventArgs)
        If TypeOf grdData.CurrentRow Is GridViewGroupRowInfo Then
            Dim groupRow As GridViewGroupRowInfo = DirectCast(grdData.CurrentRow, GridViewGroupRowInfo)
            For i As Short = 0 To groupRow.Group.ItemCount - 1
                groupRow.Group.Item(i).Cells("Percent").Value = pvGroupRowHeaderTextBoxValue 'Public Var to hold textbox value
            Next i
        End If
        pvGroupRowHeaderTextBoxValue = Nothing
    End Sub
     
    Private Sub customCell_MeCheckChanged(ByVal sender As Object, ByVal e As StateChangedEventArgs)
        If TypeOf grdData.CurrentRow Is GridViewGroupRowInfo Then
            Dim groupRow As GridViewGroupRowInfo = DirectCast(grdData.CurrentRow, GridViewGroupRowInfo)
            For i As Short = 0 To groupRow.Group.ItemCount - 1
                groupRow.Group.Item(i).Cells("Select").Value = e.ToggleState
            Next i
        End If
    End Sub
  5. Alexander
    Admin
    Alexander avatar
    306 posts

    Posted 15 Jul 2011 Link to this post

    Hello Aquariens,

    Thank you for writing back.

    The RadGridView control uses UI virtualization - its row and cell elements are created only for its visible data rows and columns and then they are reused while scrolling, sorting, grouping and so.on. In your case, the custom group header cells are reused in other group rows while scrolling.

    You can assure the correct checkbox state of the reused cells using the following approach:
    1. Mark for each group row if the cell element, associated with it, has checked state. To achieve this, you can use the ToggleStateChanged event handler of the checkbox in your custom cell:
    Private Sub checkbox_ToggleStateChanged(ByVal sender As Object, ByVal args As StateChangedEventArgs)
        RaiseEvent MeCheckChanged(Me, New StateChangedEventArgs(checkbox.ToggleState))
     
        Me.RowInfo.Tag = If(Me.checkbox.ToggleState = Enumerations.ToggleState.On, True, False)
    End Sub

    2. Override the SetContentCore method in your custom cell to update the checkbox state of the reused cells:
    Protected Overrides Sub SetContentCore(ByVal value As Object)
        MyBase.SetContentCore(value)
     
        Me.checkbox.ToggleState = If(Me.RowInfo.Tag, Enumerations.ToggleState.On, Enumerations.ToggleState.Off)
    End Sub

    I hope it helps.

    Best regards,
    Alexander
    the Telerik team

    Register for the Q2 2011 What's New Webinar Week. Mark your calendar for the week starting July 18th and book your seat for a walk through of all the exciting stuff we will ship with the new release!

  6. Me
    Me avatar
    1 posts
    Member since:
    May 2011

    Posted 17 Aug 2011 Link to this post

    Another question
    How can i access this custom group header cell from the grid valuechanged event.
    I want to change checkbox state, according to items in its group

    Thank you
  7. Alexander
    Admin
    Alexander avatar
    306 posts

    Posted 19 Aug 2011 Link to this post

    Hello Me Moyb,

    You can access the custom cell element from the ValueChanged event of RadGridView using the GetRowElement method of GridTableElement. Further, get the header row element and iterate through its cells to find the custom cell element:

    private void radGridView1_ValueChanged(object sender, EventArgs e)
    {
        GridViewGroupRowInfo groupRow = this.radGridView1.CurrentRow.Parent as GridViewGroupRowInfo;
        if (groupRow == null)
        {
            return;
        }
     
        GridGroupHeaderRowElement groupRowElement = this.radGridView1.TableElement.GetRowElement(groupRow) as GridGroupHeaderRowElement;
        if (groupRowElement == null)
        {
            return;
        }
     
        CustomGroupHeaderCell customCell = null;
        foreach (GridCellElement cell in groupRowElement.VisualCells)
        {
            customCell = cell as CustomGroupHeaderCell;
            if (customCell != null)
            {
                break;
            }
        }
     
        if (customCell != null)
        {
            // ...
        }
    }

    Please note that due to the virtualized user interface of RadGridView, the above code snippet will work only if the group row is visible. In the opposite case its row element will not be created and you should use the group data row. As an idea for suitable approach, you could review my answer to the Aquariens's question.

    Best regards,
    Alexander
    the Telerik team

    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get now >>

  8. Jes
    Jes avatar
    23 posts
    Member since:
    Feb 2009

    Posted 26 Apr 2012 Link to this post

    The code for adding a checkbox to a group header does not work for me.  No checkbox appears.  Is there something missing to get it to display or does this no longer work with the latest release?
  9. Svett
    Admin
    Svett avatar
    728 posts

    Posted 30 Apr 2012 Link to this post

    Hello Jes,

    Could you please let us know what steps you have taken in order to follow the approach? I am enclosing a sample project which demonstrates that this scenario works as expected.

    Regards,
    Svett
    the Telerik team
    RadControls for WinForms Q1'12 release is now live! Check out what's new or download a free trial >>
  10. Support
    Support avatar
    9 posts
    Member since:
    Oct 2012

    Posted 05 Nov 2012 Link to this post

    Hi there,

    Thanks for the solution above. I do have one question though.

    I have used the following code to allow checkboxes within a group header. I need to implement a "Select All" option which will check or uncheck each of the checkboxes. How can I achieve this?
    public class CustomGroupCellHeader : GridGroupContentCellElement
    {
        public event EventHandler CheckChanged;
        public RadCheckBoxElement CheckBox { get; set; }
        public GridViewColumn Column { get; set; }
        public GridRowElement Row { get; set; }
        public Guid OperatorId { get; set; }
        public string OperatorName { get; set; }
     
        public CustomGroupCellHeader(GridViewColumn column, GridRowElement row) :
            base(column, row)
        {
            this.Column = column;
            this.Row = row;
        }
     
        protected override void CreateChildElements()
        {
            base.CreateChildElements();
            this.CheckBox = new RadCheckBoxElement();
            this.CheckBox.MinSize = new Size(10, 10);
            this.CheckBox.ToggleStateChanged += new StateChangedEventHandler(_checkbox_ToggleStateChanged);
            this.Children.Insert(0, this.CheckBox);
        }
     
        protected override System.Drawing.SizeF ArrangeOverride(System.Drawing.SizeF finalSize)
        {
            SizeF size = base.ArrangeOverride(finalSize);
            RectangleF rect = GetClientRectangle(finalSize);
            if (this.CheckBox != null)
            {
                this.CheckBox.Arrange(new RectangleF(rect.X, rect.Y + 5, 10, 10));
            }
     
            return size;
        }
     
        private void _checkbox_ToggleStateChanged(object sender, StateChangedEventArgs args)
        {
            if (this.CheckChanged != null)
            {
                this.CheckChanged(this, null);
            }
        }
    }

  11. Svett
    Admin
    Svett avatar
    728 posts

    Posted 07 Nov 2012 Link to this post

    Hello,

    You can change the values of the child rows of particular group row by performing the following code snippet in the ToggleStateChanged event handler of the check box element:
    private void checkbox_ToggleStateChanged(object sender, StateChangedEventArgs args)
    {
        if (MeCheckChanged != null)
            MeCheckChanged(this, null);
     
        bool value = this.checkbox.ToggleState == ToggleState.On;
        this.RowInfo.Tag = value;
     
        ToggleRows(this.RowInfo, value);
    }
     
    private void ToggleRows(GridViewRowInfo gridViewRowInfo, bool value)
    {
        foreach (GridViewRowInfo rowInfo in gridViewRowInfo.ChildRows)
        {
            if (rowInfo is GridViewGroupRowInfo)
            {
                ToggleRows(rowInfo, value);
            }
            else
            {
                rowInfo.Cells["BooleanColumn"].Value = value;
            }
        }
    }

    I hope this helps.

    Kind regards,
    Svett
    the Telerik team
    Q3’12 of RadControls for WinForms is available for download (see what's new). Get it today.
  12. Andre
    Andre avatar
    30 posts
    Member since:
    Dec 2012

    Posted 06 Nov 2015 in reply to Svett Link to this post

    I've followed the zipped example. What i'd like to accomplish is on a button click, loop through all the header rows, see if they're checked, and perform a task.

    I'm simply trying to loop the header rows and read their state from a button click event handler.

     I'm doing this by looping though my header rows like so: 

    GridViewGroupRowInfo gi = rgvMain.Groups[i].GroupRow

    bool test = (bool)gi.Tag;

     

    My problem is that the tag value is randomly null at times.

    One other thing is, i'm using a datatable as the data source of the grid. The application can run in different modes, depending on the mode selected, the application will clear and add rows to the data table.

     

     

     

     

     
     
     
  13. Andre
    Andre avatar
    30 posts
    Member since:
    Dec 2012

    Posted 06 Nov 2015 in reply to Andre Link to this post

    I believe I've got this working. The data table was screwing things up. It seems I have to rebind the datatable to the grid after I make changes to the rows of that datatable.

    I didn't seem to have to do that up unitl I added the Custom checkbox group row.

  14. Andre
    Andre avatar
    30 posts
    Member since:
    Dec 2012

    Posted 06 Nov 2015 Link to this post

    I spoke too soon. I'm still having the original issue.
  15. Andre
    Andre avatar
    30 posts
    Member since:
    Dec 2012

    Posted 06 Nov 2015 Link to this post

    Okay, I think i'm on to something. It appears my issue isn't the underlying datatable or the binding.

    In a post above Alexander wrote:

    The RadGridView control uses UI virtualization - its row and cell elements are created only for its visible data rows and columns and then they are reused while scrolling, sorting, grouping and so.on. In your case, the custom group header cells are reused in other group rows while scrolling.

    I have 10 groups with somewhere near 20 data rows per group. On the initial display I want the first group expanded and the rest collapsed. Some of the collapsed groups don't fit in the grid window and get clipped.

    When I try to iterate the header row using

    GridViewGroupRowInfo gi = rgvMain.Groups[i].GroupRow

    bool test = (bool)gi.Tag; 

    The Tag values are null for the group header rows that are off screen/clipped. If I initially display all groups collapsed so that they're displayed on the screen, everything works fine.

    Is there a trick to get around this?


     
     
  16. Dess
    Admin
    Dess avatar
    1609 posts

    Posted 11 Nov 2015 Link to this post

    Hello Andre,

    Thank you for writing.

    By default, GridViewGroupRowInfo.Tag property is set to null. If you toggle the checkbox in the group row, you will update the GridViewGroupRowInfo.Tag property value to true. However, for the rest of the group rows that are never checked, this default null value remains. That is why you may obtain a row with Tag = null. Indeed, RadGridView uses virtualization, but only for its visual elements. GridViewGroupRowInfo is a data object and it is not reused. Hence, it is not supposed to obtain different Tag value for a group when it is in the visible grid area or not. 

    Please find attached a sample project. When the button is clicked, the Tag value is printed in the Output window. If you are still experiencing any further difficulties, it would be greatly appreciated if you explain in details what changes should I perform in order to replicate the issue locally. Alternatively, you can open a support ticket and provide a sample project demonstrating the undesired behavior.

    I hope this information helps. Should you have further questions I would be glad to help.
     
    Regards,
    Dess
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  17. Andre
    Andre avatar
    30 posts
    Member since:
    Dec 2012

    Posted 12 Nov 2015 Link to this post

    I've attached an example project that further explains the issue I'm running into. Rename the jpg. to .zip

    To reproduce, run the app, click start. Then click change mode, then click start.

    Thank you for responding, I really appreciate it. 

     

  18. Dess
    Admin
    Dess avatar
    1609 posts

    Posted 17 Nov 2015 Link to this post

    Hello Andre,

    Thank you for writing back.

    The provided sample project is greatly appreciated. You should clear the RadGridView.GroupDescriptors collection when clearing the DataTable.Rows collection. Thus, when grouping the grid, the SetContentCore method for the custom GridGroupContentCellElement will be triggered for each row:
    private void radButton1_Click(object sender, EventArgs e)
    {
        _mainTable.Rows.Clear();
        this.rgvMain.GroupDescriptors.Clear();
        for (int i = 0; i < _testCount; i++)
        {
            for (int j = 0; j < 8; j++)
            {
                DataRow dr = _mainTable.NewRow();
     
                dr.ItemArray = new object[] { true, "Other Test " + j.ToString(), i };
     
                _mainTable.Rows.Add(dr);
            }
        }
     
        rgvMain.GroupDescriptors.Add(new Telerik.WinControls.Data.GroupDescriptor("TagIndex"));
        rgvMain.MasterTemplate.GroupComparer = new GroupComparer();
    }

    I hope this information helps. If you have any additional questions, please let me know.

    Regards,
    Dess
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
Back to Top
UI for WinForms is Visual Studio 2017 Ready