Web.UI 2008.2 Grid News: Grouping

Posted Tue Sep 23, 2008 @ 11:34 AM


Now that Web.UI 2008.2 is officially out the door, I can take some time to sit back and reflect on what's been done. There are some great new controls, as usual, and major enhancements to our Grid control.

I'm particularly excited about that last part, as I've felt for a long time that some of the limitations with its grouping functionality needed to be addressed. With this release, we took the time to really re-think this aspect of the control, and instead of merely patching on additional features, to remake it in a powerful and elegant way and still keep it backward compatible. I believe we've managed to do that.

So, without further ado, here's what's new with Grid grouping:

Multiple Grouping

One of the Grid's major deficiencies for some time has been its inability to group by more than one column at a time. This had to do with various factors having to do mostly with the way we were rendering groups on the client. We have now surmounted those obstacles and groupings can be done on as many columns at a time as the user deems reasonable.

This ability extends across all running modes, usage scenarios and grouping modes.

Wait... Grouping modes?

Grouping Modes

When re-thinking the way grouping should work in Grid, we realized that there are at least three different ways in which paging through a grouped record set could work:

ConstantRecords; in this mode, the number of actual data records, regardless of how many groups they are distributed across, remains constant across pages. This mode is very simple to handle programmatically, since data-access code doesn't actually need to know anything about groupings. It simply retrieves the one page of records, which are then organized in appropriate groupings before being rendered on the client.

See demo here: ConstantRecords Grouping Mode

Thanks to its simplicity, this grouping mode is supported in all running modes, including WebService.

ConstantGroups; this mode replicates the default grouping behaviour that Grid exhibited up to this point. Paging a Grid grouped in this mode means that the same number of top-level groups is present on every page. All the contents of those groups (sub-groups and records) are pre-loaded and no additional data access is required to expand and render that content.

See demo here: ConstantGroups Grouping Mode

ConstantRows; the two modes described above have one common downside: as groups are expanded on the client, the number of rendered rows increases, and can stretch the height of the Grid control. With ConstantRows, the total number of rendered rows (records + group headings) is kept at the constant number dictated by GroupingPageSize.

See demo here: ConstantRows Grouping Mode

This running mode, when used in Server or Callback mode, requires some new server-side events (NeedGroups and NeedGroupData) to be handled in order to facilitate the efficient retrieval of only the necessary groups and records.

Which brings us to our next topic...

Grouping + Manual Paging

Up until this point, there was no good way to use manual paging (manual retrieval of just the required records from the database for each page) in conjunction with grouping with ComponentArt Grid. With the ConstantRecords and ConstantRows grouping modes, that is no longer a problem. Grouping can now be done while maintaining the efficiency of manual data retrieval.

Grouping + Scrolling

The ConstantRows grouping mode provides an additional important benefit. To support grouping in conjunction with the Grid scroller, maintaining a constant number of rendered rows was crucial. A Grid which changes its height as it is scrolled completely ruins the visual feel of a scrolling interface. With ConstantRows, grouping can finally be used with the scroller.

See a demo here: Scrolling a Grouped Grid in Callback Mode
And here: Scrolling a Grouped Grid in Client Mode

Grouping + Web Services

Grid's WebService running mode, while offering the best possible performance and elegance of design, does have limitations due its inability to perform complex server-side logic as data is loaded. This makes it difficult to support the loading of groups on the server (web service), but once again, the grouping modes greatly improve the situation.

The ConstantRecords grouping mode is easily supported in WebService running mode, since it only relies on the regular paging of records. Through this mode, grouping is now supported with web services. In the future, we will be expanding this functionality to support as much of the other two grouping modes as we can, but we feel that this is already a decent start.

See a demo here: WebService Running Mode

Conclusion

We hope you find Grid's new grouping functionality useful. We will continue to improve it and, as always, take your views and needs into account. Do let us know what you think.

Enhanced grouping isn't the only thing that's new in Grid 2008.2, but it's certainly the most significant. Nevertheless, I will be writing about the other Grid enhancements in a follow-up post. Stay tuned.

Posted to For the Love of Data by milos

Posted on Tue Sep 23, 2008 @ 11:34 AM

Filed under: , , ,

Comments

Col
Posted on Tue Sep 23, 2008 @ 11:34 AM
Does grouping now work properly on horizontally scrolling grids? I still can 't see any examples on the web site that show grouping and horizontal scrolling simultaneously.
Posted on Tue Sep 23, 2008 @ 11:34 AM

Hi i am using CA grid in my app. i have to implement both group by and filtering on key press features.. i am partially successful. If i filter the data by entering something in search box before grouping, the result is as per the expectations. But if i group the data by one(or more) of the columns available in grid and then filter the data by entering something in the search box, the data is not filtering. I tried a lot of options like changing the running mode to callback but the grid throws an error saying, there is no data to display when running mode is call back. i have followed your post at aspnetajax.componentart.com/.../WebForm1.aspx but the correct result is still alluding me. Please go through the following HTML for grid and suggest me where i am going wrong.

 <ComponentArt:Grid

                    ID="grdDevice"

                   runat="server"                    

                   PreExpandOnGroup="true"

                   AutoTheming="true"

                   RunningMode="client"                    

                   EnableViewState="false"

                   ShowSearchBox="true"

                   SearchBoxCssClass="gridSearch"

                   SliderPopupOffsetX="20"

                   SliderPopupClientTemplateId="SliderTemplate"                    

                   SearchOnKeyPress="true"                    

                   SearchText="<%$ LanguageLabel:#GeneralWords.Filter,{0}: %>"

                   SearchTextCssClass="searchText"

                   ManualPaging="true"

                   ShowHeader="true"

                   ShowFooter="true"

                   PageSize="25"

                   CssClass="aGrid"

                   DataAreaCssClass="gridData"

                   FooterCssClass="gridFooter"

                   HeaderCssClass="gridHeader"

                   PagerTextCssClass="gridFooterText"

                   PagerStyle="Numbered"

                   GroupingPageSize="10"

                   ImagesBaseUrl="~/Images/"

                   IndentCellWidth="22"

                   EmptyGridText="<%$ LanguageLabel:#GeneralPhrases.NoDevicesFound %>"

                   GroupBySortAscendingImageUrl="orderUp.png"

                   GroupBySortDescendingImageUrl="orderDown.png"

                   LoadingPanelClientTemplateId="LoadingTemplateDev"

                   LoadingPanelPosition="MiddleCenter"

                   ExpandImageUrl="plusButton.gif"

                   CollapseImageUrl="minusButton.gif"

                   AllowTextSelection="true"

                   GroupingNotificationText="<%$ LanguageLabel:#GeneralPhrases.DragToGroup %>"

                   PagerInfoClientTemplateId="pagerTemplate">                

                <Levels>

                <ComponentArt:GridLevel

                   DataKeyField="DeviceID"

                   HeadingRowCssClass="gridHeadingRow"

                   ShowTableHeading="false"

                   HeadingCellCssClass="gridHeadingCell"

                   HeadingCellHoverCssClass="gridHeadingCellHover"

                   HeadingCellActiveCssClass="gridHeadingCellActive"

                   HeadingTextCssClass="gridHeadingCellText"

                   SelectedRowCssClass="gridSelectedRow"

                   GroupHeadingCssClass="gridGroupHeading"

                   RowCssClass="gridRow"

                   HoverRowCssClass="gridRowHover"

                   AlternatingRowCssClass="gridRowAlt"

                   ShowSelectorCells="false"

                   ColumnReorderIndicatorImageUrl="reorder.png"

                   SortAscendingImageUrl="orderUp.png"

                   SortDescendingImageUrl="orderDown.png">

                    <Columns>

                       <ComponentArt:GridColumn Width="25" FixedWidth="true" DataField="Status" HeadingText=" " Visible="true" AllowGrouping="false" AllowSorting="false"

                           AllowReordering="false" IsSearchable="false"  DataCellClientTemplateId="ImageTemplateDev" />

                       <ComponentArt:GridColumn FixedWidth="true" DataField="DeviceID" HeadingText=" "  

                               AllowGrouping="false" AllowSorting="false" Visible="false" AllowReordering="false" IsSearchable="false" />

                       <ComponentArt:GridColumn DataField="ProvisioningErrors" TextWrap="false" HeadingText="<%$ LanguageLabel:GeneralWords.Error.Plural %>" AllowGrouping="false" AllowSorting="true"

                           AllowReordering="true" IsSearchable="false"/>

                       <ComponentArt:GridColumn DataField="OEMInfo" TextWrap="true" HeadingText="<%$ LanguageLabel:GeneralWords.Name %>" AllowGrouping="false" AllowSorting="true"

                           AllowReordering="true" IsSearchable="true" DataCellClientTemplateId="OEMTemplate"/>

                       <ComponentArt:GridColumn DataField="LocationGroup" HeadingText="<%$ LanguageLabel:GeneralWords.Group %>" AllowGrouping="true" AllowSorting="true"

                           AllowReordering="true" IsSearchable="true" TextWrap="true"/>

                       <ComponentArt:GridColumn DataField="LocationName" TextWrap="true" HeadingText="<%$ LanguageLabel:GeneralWords.Location %>" AllowGrouping="true" AllowSorting="true"

                           AllowReordering="true" IsSearchable="true"  DataCellClientTemplateId="LocationDevTemplate"/>

                        <ComponentArt:GridColumn DataField="IPAddress" TextWrap="false" HeadingText="<%$ LanguageLabel:DevicePhrases.IPAddress %>" AllowGrouping="true" AllowSorting="true"

                           AllowReordering="true" IsSearchable="true" Width="88" DataCellClientTemplateId="IPAddressTemplate" />

                       <ComponentArt:GridColumn DataField="LastSeen"  HeadingText="<%$ LanguageLabel:GeneralPhrases.LastActivity %>" AllowGrouping="false" AllowSorting="true"

                           AllowReordering="true" IsSearchable="true" Width="120" TextWrap="true"/>

                       <ComponentArt:GridColumn DataField="LocationID" HeadingText=" " AllowGrouping="false" AllowSorting="false"

                           AllowReordering="false" IsSearchable="false" Visible="false" />

                       <ComponentArt:GridColumn DataField="TunnelActive" Visible="false" />

                       <ComponentArt:GridColumn DataField="TunnelLastActivity" Visible="false" />

                    </Columns>

                </ComponentArt:GridLevel>

                </Levels>

                <ClientTemplates>

                    <ComponentArt:ClientTemplate Id="LoadingTemplateDev">

                       <table cellspacing="0" cellpadding="0" border="0">

                           <tr>

                            <td style="font-size:10px;"><asp:Literal ID="Literal2" runat="server" Text="<%$ LanguageLabel:GeneralWords.Loading %>" /> </td>

                           <td><img src="../Images/loading.gif" alt="<asp:Literal ID="Literal9" runat="server" Text="<%$ LanguageLabel:GeneralWords.Loading%>" />" /></td>

                           </tr>

                           </table>

                           </ComponentArt:ClientTemplate>

                   <ComponentArt:ClientTemplate ID="IPAddressTemplate" runat="server">

                       <img src="../Images/## GetTunnelerImage(DataItem.getMember("TunnelActive").get_value()) ##"

                           alt="## DataItem.getMember("TunnelLastActivity").get_value() ##"

                           title="## DataItem.getMember("TunnelLastActivity").get_value() ##" />

                       ## DataItem.getMember("IPAddress").get_value() ##

                   </ComponentArt:ClientTemplate>

                   <ComponentArt:ClientTemplate ID="ImageTemplateDev" runat="server">

                       <img src="../Images/## GetImage(DataItem.getMember("Status").get_value()) ##" />

                   </ComponentArt:ClientTemplate>

                   <ComponentArt:ClientTemplate ID="OEMTemplate" runat="server">

                      <a href="../Devices/Device.aspx?DeviceID=## DataItem.getMember("DeviceID").get_value() ##" target="_blank">## DataItem.getMember("OEMInfo").get_value() ##</a>

                   </ComponentArt:ClientTemplate>

                   <ComponentArt:ClientTemplate ID="LocationDevTemplate" runat="server">

                      <a href="../Location/LocationDetail.aspx?LocationID=## DataItem.getMember("LocationID").get_value() ##" target="_blank">## DataItem.getMember("LocationName").get_value() ## </a>

                   </ComponentArt:ClientTemplate>

                   <ComponentArt:ClientTemplate ID="pagerTemplate" runat="server">

                       ## GetPageCountDisplay() ## ## 1 + Parent.CurrentPageIndex ##  /  ## Math.max(1 , Parent.PageCount) ## (## Parent.RecordCount ## ##GetItemCountDisplay()##)

                   </ComponentArt:ClientTemplate>

                 </ClientTemplates>                                

                   </ComponentArt:Grid>

Please advice me..

Anonymous comments are not allowed. Click here to log in or create an account.