This is a migrated thread and some comments may be shown as answers.

Adding CheckBox to the Group header

16 Answers 363 Views
GridView
This is a migrated thread and some comments may be shown as answers.
Me
Top achievements
Rank 1
Me asked on 23 Jun 2011, 12:18 AM
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)
            { }
        }
    }
            
  
        
  
}

16 Answers, 1 is accepted

Sort by
0
Alexander
Telerik team
answered on 27 Jun 2011, 12:53 PM
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.
0
aquariens
Top achievements
Rank 1
answered on 14 Jul 2011, 07:46 AM
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
0
Alexander
Telerik team
answered on 15 Jul 2011, 03:22 PM
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!

0
Me
Top achievements
Rank 1
answered on 17 Aug 2011, 08:16 PM
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
0
Alexander
Telerik team
answered on 19 Aug 2011, 04:44 PM
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 >>

0
Jes
Top achievements
Rank 1
answered on 26 Apr 2012, 03:24 PM
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?
0
Svett
Telerik team
answered on 30 Apr 2012, 01:45 PM
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 >>
0
Support
Top achievements
Rank 1
answered on 05 Nov 2012, 08:25 PM
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);
        }
    }
}

0
Svett
Telerik team
answered on 07 Nov 2012, 01:44 PM
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.
0
Andre
Top achievements
Rank 1
answered on 06 Nov 2015, 11:39 PM

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.

 

 

 

 

 
 
 
0
Andre
Top achievements
Rank 1
answered on 07 Nov 2015, 01:44 AM

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.

0
Andre
Top achievements
Rank 1
answered on 07 Nov 2015, 02:04 AM
I spoke too soon. I'm still having the original issue.
0
Andre
Top achievements
Rank 1
answered on 07 Nov 2015, 02:50 AM

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?


 
 
0
Dess | Tech Support Engineer, Principal
Telerik team
answered on 11 Nov 2015, 10:53 AM
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
0
Andre
Top achievements
Rank 1
answered on 12 Nov 2015, 03:20 PM

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. 

 

0
Dess | Tech Support Engineer, Principal
Telerik team
answered on 17 Nov 2015, 08:58 AM
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
Tags
GridView
Asked by
Me
Top achievements
Rank 1
Answers by
Alexander
Telerik team
aquariens
Top achievements
Rank 1
Me
Top achievements
Rank 1
Jes
Top achievements
Rank 1
Svett
Telerik team
Support
Top achievements
Rank 1
Andre
Top achievements
Rank 1
Dess | Tech Support Engineer, Principal
Telerik team
Share this question
or