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

Expand/Collapse issues using Grouping

3 Answers 418 Views
Grid
This is a migrated thread and some comments may be shown as answers.
Curtis
Top achievements
Rank 1
Curtis asked on 27 Feb 2012, 08:55 PM
We recently upgraded from the ASP.NET Classic controls to the ASP.NET AJAX controls on one of our largest projects.  One of our requirements was to maintain current behavior and appearance on all controls.  Unfortuantely, we are having a fair amount of trouble with RadGrids. 

We are using a RadGrid with server side grouping and expand/collapse functionality enabled.  When a user expands/collapses an item, the ItemCommand event is fired which updates a session variable to keep track of which items are expanded.  When the user returns to the page, the ItemDataBound method determines whether or not to expand a GridGroupHeaderItem depending on the values stored in the session variable.  The good news is that expanded/collapsed states are rendering correctly on subsequent page loads.  Unfortunately, if the user then expands or collapses any item, all GridItems that were expanded in the ItemDataBound disappear.  The groups that these items belong to are still expanded and items that have been expanded after page load are not affected.  Clicking on the group again collapses the group with the missing items, and the next click re-expands it revealing the items that were missing.

Does anyone have any idea why our items are being hidden?  I included snippets from the aspx and aspx.cs files below.  Specific names and details have been changed to protect the innocent.

...
 
<telerik:RadAjaxManager runat="server" ID="radAjaxManager" EnableAJAX="true" OnAjaxRequest="RadAjaxManager_AjaxRequest">
    <AjaxSettings>
        <telerik:AjaxSetting AjaxControlID="radAjaxManager">
            <UpdatedControls>
                <telerik:AjaxUpdatedControl ControlID="radGrid1" />
            </UpdatedControls>
        </telerik:AjaxSetting>
    </AjaxSettings>
</telerik:RadAjaxManager>
 
...
 
<telerik:RadGrid ID="radGrid1" runat="server" AllowFilteringByColumn="false" AllowPaging="false" AllowSorting="true" AutoGenerateColumns="false" EnableEmbeddedSkins="false" GroupingEnabled="true"
    OnItemCommand="radGrid1_ItemCommand" OnItemDataBound="radGrid1_ItemDataBound" OnNeedDataSource="radGrid1_NeedDataSource"
    ShowGroupPanel="false" ShowHeader="true" Skin="XYZ">
    <ClientSettings AllowColumnsReorder="true" AllowGroupExpandCollapse="true" AllowDragToGroup="false" ReorderColumnsOnClient="true">
        <Resizing AllowColumnResize="false" AllowRowResize="false" EnableRealTimeResize="false" ResizeGridOnColumnResize="false"/>
        <ClientEvents OnGridCreated="radGrid1_GridCreated" />
    </ClientSettings>
    <MasterTableView AllowMultiColumnSorting="false" DataKeyNames="Data1, Data2"
        GroupLoadMode="Server" GroupsDefaultExpanded="false" ShowHeader="true" Name="mtvRadGrid1"
        NoDetailRecordsText="There are no items that match your request."
        NoMasterRecordsText="There are no items that match your request." ShowFooter="false">
        <GroupByExpressions>
            <telerik:GridGroupByExpression>
                <SelectFields>
                    <telerik:GridGroupByField Aggregate="First" FieldAlias="Group1NameAlias" FieldName="Group1Name"/>
                    <telerik:GridGroupByField Aggregate="First" FieldAlias="Group1IdAlias" FieldName="Group1Id"/>
                </SelectFields>
                <GroupByFields>
                    <telerik:GridGroupByField FieldName="Group1Name" SortOrder="Ascending" />
                </GroupByFields>
            </telerik:GridGroupByExpression>
            <telerik:GridGroupByExpression>
                <SelectFields>
                    <telerik:GridGroupByField Aggregate="First" FieldAlias="Group2NameAlias" FieldName="Group2Name"/>
                    <telerik:GridGroupByField Aggregate="First" FieldAlias="Group2IdAlias" FieldName="Group2Id"/>
                </SelectFields>
                <GroupByFields>
                    <telerik:GridGroupByField FieldName="Group2Name" SortOrder="Ascending" />
                </GroupByFields>
            </telerik:GridGroupByExpression>
        </GroupByExpressions>
        <Columns>
            <telerik:GridBoundColumn UniqueName="ColumnA" DataField="ColumnA" />
            <telerik:GridBoundColumn UniqueName="ColumnB" DataField="ColumnB" />
            ...
            <telerik:GridTemplateColumn UniqueName="link" HeaderText="Link" Groupable="false" SortExpression="sortExpression" HeaderStyle-HorizontalAlign="Left" >
                <ItemTemplate>
                    <asp:HyperLink ID="itemLink" runat="server"></asp:HyperLink>
                </ItemTemplate>
            </telerik:GridTemplateColumn>
                ...
        </Columns>
    </MasterTableView>
</telerik:RadGrid>


protected void radGrid1_ItemDataBound(object source, GridItemEventArgs e)
{
    if (e.Item.ItemType == GridItemType.GroupHeader)
    {
        GridGroupHeaderItem item = (GridGroupHeaderItem)e.Item;
        DataRowView groupDataRow = (DataRowView)e.Item.DataItem;
 
        // Telerik does not allow public access to the GroupLevel property of GridItems.
        // Unfortunately, this is the only way we have found to determine the group level.
        // The GroupIndex is formatted as "Group1_Group2_Group3"
        string[] headerItemGroups = e.Item.GroupIndex.Split('_');
 
        string group1Name;
        string group2Name;
 
        int group1Id;
        int group2Id;
        int headerItemGroupLevel = headerItemGroups.Length - 1; // GroupLevel is 0 based
 
        if (headerItemGroupLevel == 0)
        {
            List<int> expandedGroup1IdList = GetSessionExpandedGroup1IdList();
 
            group1Name = groupDataRow["Group1Name"].ToString();
            group1Id = (int)groupDataRow["Group1Id"];
                 
            // Telerik does not allow access to DataKeyValues in the GridGroupHeaderItems hence the horrible code below.
            // We can add a group by field to the header, grab it on ItemDataBound, and then replace it with meaningful text
            item.DataCell.Text = "Group1: " + group1Name;
            item.Expanded = expandedGroup1IdList.Contains(group1Id);
        }
        else if (headerItemGroupLevel == 1)
        {
            List<int> expandedGroup2IdList = GetSessionExpandedGroup2IdList();
 
            group2Name = groupDataRow["Group2Name"].ToString();
            group2Id = (int)groupDataRow["Group2Id"];
 
            // Telerik does not allow access to DataKeyValues in the GridGroupHeaderItems hence the horrible code below.
            // We can add a group by field to the header, grab it on ItemDataBound, and then replace it with meaningful text
            item.DataCell.Text = "Group2: " + group2Name;
            item.Expanded = expandedGroup2IdList.Contains(group2Id);
        }
    }
    else if (e.Item.ItemType == GridItemType.Item)
    {
        Class1 dataItem= (Class1)e.Item.DataItem;
 
        HyperLink link = (HyperLink)e.Item.FindControl("itemLink");
 
        if (dataItem.property == ...)
        {
            link.NavigateUrl = ...
            link.Text = ...
        }
        else if (dataItem.property == ...)
        {
            link.NavigateUrl = ...
            link.Text = ...
        }
    }
}
 
protected void radGrid1_ItemCommand(object source, GridCommandEventArgs e)
{
    if (e.CommandName == RadGrid.ExpandCollapseCommandName)
    {
        // Telerik does not allow public access to the GroupLevel property of GridItems.
        // Unfortunately, this is the only way we have found to determine the group level.
        // The GroupIndex is formatted as "Group1_Group2_Group3"
        string[] headerItemGroups = e.Item.GroupIndex.Split('_');
        string[] dataItemGroups;
 
        int group1Id;
        int group2Id;
        int headerItemGroupLevel = headerItemGroups.Length - 1; // Group Level is 0 based
 
        bool isExpanded = !e.Item.Expanded; // The item is currently expanding/collapsing so the state is yet to change
 
        foreach (GridDataItem item in e.Item.OwnerTableView.Items)
        {
            dataItemGroups = item.GroupIndex.Split('_');
 
            // Telerik does not provide access to DataKeyValues from GridGroupHeaderItems
            // Loop through all items in the MasterTableView until we find an item that belongs to the group(s) of the clicked item
            // Save the appropriate IDs in a session variable to track which items are expanded
            if (headerItemGroupLevel == 0 && headerItemGroups[0] == dataItemGroups[0])
            {
                group1Id = (int)item.GetDataKeyValue("Group1Id");
 
                SaveSessionExpandedGroup1IdList(group1Id, isExpanded);
 
                break;
            }
            else if (headerItemGroupLevel == 1 && headerItemGroups[0] == dataItemGroups[0] && headerItemGroups[1] == dataItemGroups[1])
            {
                group2Id = (int)item.GetDataKeyValue("group2Id");
 
                SaveSessionExpandedGroup2IdList(group2Id, isExpanded);
 
                break;
            }
        }
    }
}

3 Answers, 1 is accepted

Sort by
0
Marin
Telerik team
answered on 01 Mar 2012, 01:08 PM
Hello Curtis,

 We have already addressed the support ticket opened on the same subject. Please avoid posting duplicate threads since this confuses our support officers. If you do not mind we will continue the communication in the support ticket that was opened.
For the benefit of the community I am also posting the answer here:

The ItemDataBound event is fired too late in the grid's life cycle and that's why items that should be shown after expanding are not databound properly and are not visible. A better approach would be traverse the items after the grid is databound, for example in the Page_PreRender event. There you can use the same logic to set which items should be expanded and then rebind the control again. This should also render the child items for each group. 

protected void Page_PreRender(object sender, EventArgs e)
    {
        var headerItems = RadGrid1.MasterTableView.GetItems(GridItemType.GroupHeader);
        foreach (GridHeaderItem item in headerItems)
        {
            if (item should be expanded)
            {
                item.Expanded = true;
            }
        }
        RadGrid1.Rebind();
    }

Kind regards,
Marin
the Telerik team
If you want to get updates on new releases, tips and tricks and sneak peeks at our product labs directly from the developers working on the RadControls for ASP.NET AJAX, subscribe to their blog feed now.
0
Pavel
Top achievements
Rank 1
answered on 12 Apr 2016, 05:43 PM

Sorry to be bringing up such and old post back from the dead, but this isn't working for me.

I am putting the relevant code below, with a few things removed for clarity.

I can walk through with a debugger, and I know that the .expanded property is getting set correctly, but i can't get it to work.

<uc1:CommonGrid ID="myGrid" runat="server" EnableEmbeddedSkins="False"
    ShowStatusBar="true"
    AutoGenerateColumns="false"
    ClientSettings-AllowGroupExpandCollapse="true"
    ClientSettings-Selecting-AllowRowSelect="True"
    AllowMultiRowSelection="True"
    AllowAutomaticUpdates="True"
    AllowAutomaticInserts="False"
    AllowAutomaticDeletes="False"
    AutoGenerateEditColumn="False">   
     
    <MasterTableView AutoGenerateColumns="False"
        Summary="Measure Categories"
        DataKeyNames="CategoryId,CategoryName"
        AllowSorting="true"
        AllowNaturalSort="false"
        ShowHeadersWhenNoRecords="True"
        GroupLoadMode="Client"
        CommandItemDisplay="None"
        GroupsDefaultExpanded="false">

protected void Page_PreRender(object sender, EventArgs e)
{
    foreach (GridGroupHeaderItem groupHeader in myGrid.MasterTableView.GetItems(GridItemType.GroupHeader))
    {
        var children = groupHeader.GetChildItems();
        var expanded = false;
 
        foreach (GridDataItem child in children)
        {
            if (child.Selected)
            {
                expanded = true;
                break;
            }
        }
        groupHeader.Expanded = expanded;
    }
    myGrid.Rebind();
}

0
Marin
Telerik team
answered on 15 Apr 2016, 05:02 PM
Hi,

When you use GroupLoadMode="Client" the groups are only expanded or collapsed on the client so we recommend to move the logic from Page_PreRender on the client. You can use our client-side API in this case:
http://docs.telerik.com/devtools/aspnet-ajax/controls/grid/client-side-programming/gridtableview-object/methods/expandgroup

http://docs.telerik.com/devtools/aspnet-ajax/controls/grid/client-side-programming/gridtableview-object/methods/collapsegroup

I hope this helps. Let me know if you have any other questions.

Regards,
Marin
Telerik
Do you need help with upgrading your ASP.NET AJAX, WPF or WinForms projects? Check the Telerik API Analyzer and share your thoughts.
Tags
Grid
Asked by
Curtis
Top achievements
Rank 1
Answers by
Marin
Telerik team
Pavel
Top achievements
Rank 1
Share this question
or