Hi,
I have two levels of grouping in my RadGrid:
| <telerik:RadGrid ID="uxByAgeAndGenderGrid" runat="server" AutoGenerateColumns="false" CssClass="gridAlternatingRows" |
| OnItemDataBound="uxByAgeAndGenderGrid_OnItemDataBound" OnNeedDataSource="uxByAgeAndGenderGrid_OnNeedDataSource"> |
| <MasterTableView GroupLoadMode="Client" ShowGroupFooter="true" HeaderStyle-Font-Bold="true" ShowFooter="true"> |
| <GroupByExpressions> |
| <telerik:GridGroupByExpression> |
| <SelectFields> |
| <telerik:GridGroupByField FieldName="RequestedGender" HeaderText=" " HeaderValueSeparator="" /> |
| </SelectFields> |
| <GroupByFields> |
| <telerik:GridGroupByField FieldName="RequestedGender" /> |
| </GroupByFields> |
| </telerik:GridGroupByExpression> |
| <telerik:GridGroupByExpression> |
| <SelectFields> |
| <telerik:GridGroupByField FieldName="RequestedMinAge" HeaderText=" " HeaderValueSeparator="" /> |
| </SelectFields> |
| <GroupByFields> |
| <telerik:GridGroupByField FieldName="RequestedMinAgeRank" /> |
| </GroupByFields> |
| </telerik:GridGroupByExpression> |
| </GroupByExpressions> |
| <Columns> |
| <telerik:GridBoundColumn DataField="Status" HeaderText="Status" SortExpression="StatusRank"> |
| </telerik:GridBoundColumn> |
| <telerik:GridBoundColumn DataField="NewCount" HeaderText="New invitations" Aggregate="Sum" FooterText="Total: "> |
| </telerik:GridBoundColumn> |
| <telerik:GridBoundColumn DataField="ReinviteCount" HeaderText="Re-invite invitations" Aggregate="Sum" FooterText="Total: "> |
| </telerik:GridBoundColumn> |
| <telerik:GridBoundColumn DataField="AskedForCount" HeaderText="Asked For invitations" Aggregate="Sum" FooterText="Total: "> |
| </telerik:GridBoundColumn> |
| <telerik:GridBoundColumn DataField="TotalCount" HeaderText="Total" Aggregate="Sum" FooterText="Grand total: "> |
| </telerik:GridBoundColumn> |
| </Columns> |
| </MasterTableView> |
| </telerik:RadGrid> |
And I would like to have both levels of grouping collapsed by default. I've tried the following property on the MasterTableView:
| GroupsDefaultExpanded="false" |
But this only seems to collapse the top grouping level. When you expand on of the top groups, all of its subgroups open up expanded!
So next, I tried the following in the OnLoad method, as instructed by http://www.telerik.com/help/aspnet-ajax/grdcollapseallitemsongrouping.html:
| if (!IsPostBack) |
| { |
| uxByAgeAndGenderGrid.Rebind(); |
| foreach (GridItem item in uxByAgeAndGenderGrid.MasterTableView.Controls[0].Controls) |
| { |
| if (item is GridGroupHeaderItem) |
| { |
| item.Expanded = false; |
| } |
| } |
| } |
But I get the following error:
| Server Error in '/' Application. |
| StartIndex cannot be less than zero. |
| Parameter name: startIndex |
| Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. |
| Exception Details: System.ArgumentOutOfRangeException: StartIndex cannot be less than zero. |
| Parameter name: startIndex |
| Source Error: |
| Line 37: if (item is GridGroupHeaderItem) |
| Line 38: { |
| Line 39: item.Expanded = false; |
| Line 40: } |
| Line 41: } |
| Source File: C:\VS\Flive\Main\Source\FliveSolution\Freshair.Flive\Experiences\FriendlyTown\FtByTheNumbers.aspx.cs Line: 39 |
| Stack Trace: |
| [ArgumentOutOfRangeException: StartIndex cannot be less than zero. |
| Parameter name: startIndex] |
| System.String.Remove(Int32 startIndex) +6576122 |
| Telerik.Web.UI.GridGroupHeaderItem.GroupFooterByHeaderIndexAndSequenceNumber(String groupIndex, Int32 seqNum) +202 |
| Telerik.Web.UI.GridGroupHeaderItem.SetVisibleChildren(Boolean value) +794 |
| Telerik.Web.UI.GridItem.set_Expanded(Boolean value) +126 |
| Freshair.Flive.Experiences.FriendlyTown.FtByTheNumbersPage.OnLoad(EventArgs e) in C:\VS\Flive\Main\Source\FliveSolution\Freshair.Flive\Experiences\FriendlyTown\FtByTheNumbers.aspx.cs:39 |
| System.Web.UI.Control.LoadRecursive() +71 |
| System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +3048 |
| Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.1 |
The OnNeedDataSource looks like this:
| protected void uxByAgeAndGenderGrid_OnNeedDataSource(Object sender, GridNeedDataSourceEventArgs e) |
| { |
| Int32 programYear = DateTime.Today.GetChildApplicationProgramYear(); |
| var childrenWhoParticipatedInPreviousYears = |
| from child in Ctx.Persons |
| join vep in Ctx.ViewExperienceParticipations on child.PersonId equals vep.PersonId |
| join status in Ctx.ExperienceEligibilityPersonParticipationStatus on vep.CurrentStatusId equals status.ExperienceEligibilityPersonParticipationStatusId |
| join ee in Ctx.ExperienceEligibilities on vep.ExperienceEligibilityId equals ee.ExperienceEligibilityId |
| join exp in Ctx.Experiences on ee.ExperienceId equals exp.ExperienceId |
| join et in Ctx.ExperienceTypes on exp.ExperienceTypeId equals et.ExperienceTypeId |
| where !status.NullifiesParticipation |
| where status.ExperienceEligibilityPersonParticipationStatusId != 1 // Other than Invited |
| where exp.FromDate.Value.Year < programYear |
| select new |
| { |
| child.PersonId, |
| exp.HostingHouseholdId |
| }; |
| List<String> statusRank = new List<String>(); |
| statusRank.Add("Matched"); |
| statusRank.Add("Open"); |
| statusRank.Add("Invited"); |
| statusRank.Add("Placed"); |
| statusRank.Add("Refused"); |
| statusRank.Add("Not Found"); |
| statusRank.Add("Excused"); |
| statusRank.Add("Proposed New Dates"); |
| statusRank.Add("Must Approve Trip Dates"); |
| statusRank.Add("Child proposed new dates"); |
| statusRank.Add("Child must approve dates"); |
| statusRank.Add("Didn't Show"); |
| statusRank.Add("Attended"); |
| statusRank.Add("Returned Early"); |
| statusRank.Add("Transferred Out"); |
| statusRank.Add("Canceled"); |
| statusRank.Add("Closed by child"); |
| statusRank.Add("Withdrawn by host"); |
| statusRank.Add("Change In Progress"); |
| List<String> ageRank = new List<String>(); |
| ageRank.Add("0 to 5"); |
| ageRank.Add("6 to 8"); |
| ageRank.Add("9 to 10"); |
| ageRank.Add("11 to 12"); |
| ageRank.Add("Over 13"); |
| ageRank.Add("Unknown"); |
| DateTime today = DateTime.Today; |
| var invitations = |
| (from exp in Ctx.Experiences |
| join et in Ctx.ExperienceTypes on exp.ExperienceTypeId equals et.ExperienceTypeId |
| join ec in Ctx.ExperienceCategories on et.ExperienceCategoryId equals ec.ExperienceCategoryId |
| join vee in Ctx.ViewActiveEligibilityByExperiences on exp.ExperienceId equals vee.ExperienceId |
| join ee in Ctx.ExperienceEligibilities on vee.ExperienceEligibilityId equals ee.ExperienceEligibilityId |
| join reqPerson in Ctx.Persons on ee.PersonId equals reqPerson.PersonId into reqPersons |
| from reqPerson in reqPersons.DefaultIfEmpty() |
| join part in Ctx.ViewExperienceParticipations on ee.ExperienceEligibilityId equals part.ExperienceEligibilityId into parts |
| from part in parts.DefaultIfEmpty() |
| join person in Ctx.Persons on part.PersonId equals person.PersonId into persons |
| from person in persons.DefaultIfEmpty() |
| join status in Ctx.ExperienceEligibilityPersonParticipationStatus on part.CurrentStatusId equals status.ExperienceEligibilityPersonParticipationStatusId into statuses |
| from status in statuses.DefaultIfEmpty() |
| join searchParam in Ctx.ViewInvitationEligibilityParameters on ee.SearchId equals searchParam.SearchId into searchParams |
| from searchParam in searchParams.DefaultIfEmpty() |
| where exp.FromDate.GetValueOrDefault(new DateTime(1877, 1, 1)).Year == programYear |
| where et.ExperienceCategoryId == 1 |
| where part == null || part.ExperienceEligibilityPersonParticipationTypeId == 1 // Child |
| where person == null || person.PersonId != 30190 |
| select new |
| { |
| RequestedGender = reqPerson == null ? (searchParam == null ? "Unknown" : |
| (searchParam.Gender == null ? "Either a boy or a girl" : |
| (searchParam.Gender == "M" ? "Only a boy" : "Only a girl"))) : |
| (reqPerson.Gender == null ? "Unknown" : (reqPerson.Gender == "M" ? "Only a boy" : "Only a girl")), |
| RequestedMinAge = reqPerson == null ? (searchParam == null ? -1 : |
| (searchParam.MinAge == null ? -1 : searchParam.MinAge)) : |
| (reqPerson.BirthDate == null ? -1 : Ctx.FuncGetAge(reqPerson.BirthDate, today)), |
| IsNew = ee.SearchId != null ? true : false, |
| IsReinvite = ee.PersonId == null ? false : |
| (childrenWhoParticipatedInPreviousYears.Where(p => p.PersonId == ee.PersonId && p.HostingHouseholdId == exp.HostingHouseholdId).Count() > 0 ? true : false), |
| Program = ec.Name, |
| StatusId = status == null ? 0 : status.ExperienceEligibilityPersonParticipationStatusId, |
| IsWithdrawn = exp.IsCanceled |
| }).ToArray(); |
| var invitations2 = |
| (from invitation in invitations |
| group new |
| { |
| IsNew = invitation.IsNew, |
| IsReinvite = invitation.IsReinvite |
| } by new |
| { |
| RequestedGender = invitation.RequestedGender, |
| RequestedMinAge = invitation.RequestedMinAge < 0 ? "Unknown" : |
| (invitation.RequestedMinAge < 6 ? "0 to 5" : |
| (invitation.RequestedMinAge < 9 ? "6 to 8" : |
| (invitation.RequestedMinAge < 11 ? "9 to 10" : |
| (invitation.RequestedMinAge < 13 ? "11 to 12" : "Over 13")))), |
| Status = invitation.IsWithdrawn ? "Withdrawn by host" : FtLogicController.GetInvitationStatusByCurrentParticipationStatus(invitation.StatusId).GetStatusText() |
| } into grouping |
| select grouping).ToArray(); |
| var invitationsToBind = |
| from grouping in invitations2 |
| select new |
| { |
| RequestedGender = grouping.Key.RequestedGender, |
| RequestedMinAge = grouping.Key.RequestedMinAge, |
| RequestedMinAgeRank = ageRank.IndexOf(grouping.Key.RequestedMinAge), |
| Status = grouping.Key.Status, |
| StatusRank = statusRank.IndexOf(grouping.Key.Status), |
| NewCount = grouping.Count(p => p.IsNew), |
| ReinviteCount = grouping.Count(p => p.IsReinvite), |
| AskedForCount = grouping.Count(p => !p.IsReinvite && !p.IsNew), |
| TotalCount = grouping.Count() |
| }; |
| uxByAgeAndGenderGrid.GroupingSettings.RetainGroupFootersVisibility = true; |
| uxByAgeAndGenderGrid.DataSource = invitationsToBind.OrderBy(p => p.StatusRank); |
| uxInvitationsToBeFilled.Text = invitationsToBind.Where(p => p.Status == "Open").Sum(p => p.TotalCount).ToString(); |
| uxMatchedInvitationsNotYetDeparted.Text = invitationsToBind.Where(p => p.Status == "Matched").Sum(p => p.TotalCount).ToString(); |
| } |
Any ideas?
Many thanks,
Jake
(And in case you're wondering what in the world is going on here, this is a report of invitations tendered by volunteer host families for The Fresh Air Fund - www.freshair.org.)