Working with Groups in Code

  • 10 minutes to read

Group and Ungroup Data

GridColumn.Group

Groups data against this column. If data is already grouped by other columns, this column will be added to the end of the grouping queue.

GridColumn.UnGroup

Removes data grouping by this column.

GridView.ClearGrouping

Removes all data grouping.

GridColumn.GroupIndex

Accepts non-negative integer values that specify the column order according to which data is grouped. Values must be unique, which means you cannot apply merged column grouping by setting column group indexes. You can change this property only for columns that have already been added to a View.

ColumnView.SortInfo

A collection that stores specific ColumnSortInfo objects on every grid column involved in sorting and grouping. To apply complex grouping in code, modify this collection manually by calling the GridColumnSortInfoCollection.ClearAndAddRange method. The code below applies two grouping layers: merged grouping by "Ship Country", "Ship City" and "Ship Region" columns, followed by tier two grouping by the "Customer ID" column.


gridView1.SortInfo.ClearAndAddRange(new[] {
    new GridMergedColumnSortInfo(
        new[] {
            colShipCountry, colShipCity, colShipRegion},
        new[] {
            ColumnSortOrder.Ascending, ColumnSortOrder.Descending, ColumnSortOrder.Ascending }),
    new GridColumnSortInfo(colCustomerID, ColumnSortOrder.Descending)
}, 4);

ColumnView.StartGrouping, ColumnView.EndGrouping

Non-cancelable events that fire whenever a grouping operation takes place.

Modify Group Row Content

GridView.GroupFormat, GridColumn.GroupFormat

Allows you to modify group row content for individual Grid columns, or all columns at once.

GridView.CustomDrawGroupRow

Allows you to modify specific group row captions.


colShipCountry.GroupInterval = DevExpress.XtraGrid.ColumnGroupInterval.Alphabetical;

private void gridView1_CustomDrawGroupRow(object sender, DevExpress.XtraGrid.Views.Base.RowObjectCustomDrawEventArgs e) {
    GridGroupRowInfo info = e.Info as GridGroupRowInfo;
    if (info.Column == colShipCountry) {
        info.GroupText = "Ship country starts with " + info.GroupValueText;
    }
}

GridOptionsBehavior.AlignGroupSummaryInGroupRow

Allows you to display group summaries within group rows.

AlignGroupSummaryInGroupRow

Custom Grouping

GridColumn.SortMode

Set this property to Custom to implement custom grouping.

GridView.CustomColumnGroup

Fires for all columns with the custom sort mode when grid data is grouped against these columns. Allows you to implement custom grouping algorithms.

ColumnView.CustomColumnDisplayText or GridView.CustomDrawGroupRow

Handle any of these events to modify group row captions accordingly to your custom grouping algorithms. The sample below illustrates how to break order dates into four seasons and group orders by these seasons.

Grid - Custom Grouping


using System;
using DevExpress.XtraGrid.Views.Grid;
using DevExpress.XtraGrid.Views.Base;
using DevExpress.XtraGrid.Views.Grid.ViewInfo;
using System.Collections.Generic;
using DevExpress.XtraGrid.Columns;

namespace CustomGroupingSample {
    public partial class XtraForm1 : DevExpress.XtraEditors.XtraForm {
        public XtraForm1() {
            InitializeComponent();
            // This line of code is generated by Data Source Configuration Wizard
            ordersTableAdapter1.Fill(_Northwind2010___CopyDataSet11.Orders);
            gridView1.OptionsView.ShowGroupedColumns = true;
            gridView1.SortInfo.ClearAndAddRange(new[] {
                new GridColumnSortInfo(colOrderDate, DevExpress.Data.ColumnSortOrder.Ascending)
            });

            colOrderDate.SortMode = DevExpress.XtraGrid.ColumnSortMode.Custom;
            gridView1.CustomColumnGroup += GridView1_CustomColumnGroup;
            gridView1.CustomColumnDisplayText += GridView1_CustomColumnDisplayText;
            //or
            gridView1.CustomDrawGroupRow += GridView1_CustomDrawGroupRow;
        }

        //Custom Grouping
        private void GridView1_CustomColumnGroup(object sender, CustomColumnSortEventArgs e) {
            if (e.Column == colOrderDate) {
                DateTime value1 = (DateTime)e.Value1;
                DateTime value2 = (DateTime)e.Value2;
                if (GetSeason(value1) == GetSeason(value2)) e.Result = 0;
                else e.Result = 1;
                e.Handled = true;
            }
        }


        //Get season by date
        private string GetSeason(DateTime date) {
            Int32 month = date.Month;
            string season = "Winter";
            if (month == 3 || month == 4 || month == 5) season = "Spring";
            if (month == 6 || month == 7 || month == 8) season = "Summer";
            if (month == 9 || month == 10 || month == 11) season = "Fall";
            return season;
        }

        //Custom group row content  (option #1)
        private void GridView1_CustomColumnDisplayText(object sender, CustomColumnDisplayTextEventArgs e) {
            GridView view = sender as GridView;
            if (view == null) return;
            if (e.Column == colOrderDate && e.IsForGroupRow) {
                DateTime rowValue = (DateTime)view.GetGroupRowValue(e.GroupRowHandle, e.Column);
                string season = GetSeason(rowValue);
                if (season != "Winter") e.DisplayText = season + " " + rowValue.Year;
                else e.DisplayText = season + " " + rowValue.Year + "/" + rowValue.AddYears(1).Year;
            }
        }

        //Custom group row content  (option #2)
        private void GridView1_CustomDrawGroupRow(object sender, DevExpress.XtraGrid.Views.Base.RowObjectCustomDrawEventArgs e) {
            GridGroupRowInfo info = e.Info as GridGroupRowInfo;
            GridView view = sender as GridView;
            if (info.Column == colOrderDate) {
                DateTime rowValue = (DateTime)view.GetGroupRowValue(info.RowHandle, info.Column);
                string season = GetSeason(rowValue);
                if (season != "Winter") info.GroupText = "Order Date: " + season + " " + rowValue.Year;
                else info.GroupText = "Order Date: " + season + " " + rowValue.Year + "/" + rowValue.AddYears(1).Year;
            }
        }
    }
}

Locate and Process Group Rows

Row Handles

Row handles are integer values that identify both data (positive values) and group (negative values) rows.

Grid - Group Row Handles

GridView.GetRowLevel

Identifies the nesting level of a row.

Grid - Row Levels

GridView.GetChildRowCount

Returns the number of immediate child rows for a group row.

GridView.GetChildRowHandle

Returns the row handle of a group row's child data row. The following example shows how to change the "Price" column value for all the data rows belonging to the focused data group. Prices change when end-users press the "Discount" button.


using DevExpress.XtraGrid.Views.Grid;
//... 
private void buttonDiscount_Click(object sender, System.EventArgs e) {
    GridView view = gridView1;
    int rowHandle = view.FocusedRowHandle;
    ArrayList rowsToDiscount = new ArrayList();
    //Get related data rows 
    if(view.IsGroupRow(rowHandle))
        getChildRows(view, rowHandle, rowsToDiscount);
    else 
        rowsToDiscount.Add(view.GetRow(rowHandle));
    //Change the values of the rows 
    view.BeginUpdate();
    discount(rowsToDiscount);
    view.EndUpdate();
}

//Returns the child data rows for the given group row 
public void getChildRows(GridView view, int groupRowHandle, ArrayList childRows) {
    if(!view.IsGroupRow(groupRowHandle)) return;
    //Get the number of immediate children 
    int childCount = view.GetChildRowCount(groupRowHandle);
    for(int i=0; i<childCount; i++){
        //Get the handle of a child row with the required index 
        int childHandle = view.GetChildRowHandle(groupRowHandle, i);
        //If the child is a group row, then add its children to the list 
        if(view.IsGroupRow(childHandle))
            getChildRows(view, childHandle, childRows);
        else {                    
            // The child is a data row.  
            // Add it to the childRows as long as the row wasn't added before 
            object row = view.GetRow(childHandle);
            if(!childRows.Contains(row))
                childRows.Add(row);
        }       
    }
}

//Changes the values of the Price column for the specified rows 
public void discount(ArrayList rows) {
    for(int i = 0; i < rows.Count; i++) {
        DataRow row = (rows[i] as DataRowView).Row;    
        decimal oldValue = (decimal)row["Price"];
        row["Price"] = oldValue * 0.95m;               
    }
}

GridView.GetParentRowHandle

Returns the row handle of a parent row.

ColumnView.GetRow/ColumnView.GetDataRow

Methods that retrieve System.Data.DataRowView or other objects, which represent data source rows.

Expand and Collapse Rows

GridView.GetRowExpanded

Returns whether or not the row is expanded.

GridView.ExpandGroupRow/GridView.CollapseGroupRow

Call this method to expand or collapse a row.

GridView.SetRowExpanded

Expands or collapses a row itself and (optionally) all of its child rows.

GridView.GroupRowExpanding/GridView.GroupRowCollapsing

Cancelable events that fire when a group is to be expanded or collapsed.

GridView.GroupRowExpanded/GridView.GroupRowCollapsed

These events occur after a row has been expanded or collapsed.

ColumnView.FocusedRowHandle

Scrolls the View to display the required row and selects this row. Expands the row's parent group.

GridView.MakeRowVisible

Scrolls the View to display the required row. If the row belongs to a group, this group expands. The code snippet below displays all rows whose "InStock" column values equal false.


using DevExpress.XtraGrid.Views.Grid;
//... 
GridView View = gridView1;
int rowHandle = -1;
do {
    rowHandle = View.LocateByValue(rowHandle+1, View.Columns["Is In Stock"], false);
    View.MakeRowVisible(rowHandle, false);
} while(rowHandle != GridControl.InvalidRowHandle);
See Also