windowsforms-1967-controls-and-libraries-data-grid-grouping-working-with-groups-in-code.md
Use the following API to group data in code:
|
API
|
Description
| | --- | --- | |
|
Groups data by the current column. If data is already grouped by other columns, the column is added after the last grouping level.
| |
|
Specifies the grouping order. Accepts non-negative integer values.
Tip
Set the column’s GroupIndex property to a unique value when using merged column grouping.
| |
|
Removes grouping applied to the column. This method does not affect other grouped columns.
| |
|
Removes all data grouping and reverts the grid to an ungrouped state.
|
The following code snippet groups data by the Ship Country column and then by the Ship City column:
public Form1() {
colShipCountry.Group();
colShipCity.Group();
// Or
colShipCountry.GroupIndex = 0;
colShipCity.GroupIndex = 1;
}
Public Sub New()
colShipCountry.Group()
colShipCity.Group()
' Or
colShipCountry.GroupIndex = 0
colShipCity.GroupIndex = 1
End Sub
The following code snippet removes grouping by the last-level column when the button is clicked:
void removeLastGroupingButton_Click(object sender, EventArgs e) {
if (gridView1.GroupedColumns.Count > 0)
gridView1.GroupedColumns.Last().UnGroup();
}
Private Sub removeLastGroupingButton_Click(ByVal sender As Object, ByVal e As EventArgs)
If gridView1.GroupedColumns.Count > 0 Then
gridView1.GroupedColumns.Last().UnGroup()
End If
End Sub
A grouping operation raises ColumnView.StartGrouping and ColumnView.EndGrouping events. These events do not allow you to cancel the grouping operation.
Use the GridColumnSortInfoCollection.ClearAndAddRange method to modify the ColumnView.SortInfo collection. This collection stores ColumnSortInfo objects for every column involved in sorting and grouping.
The following code snippet applies two grouping layers:
gridView1.SortInfo.ClearAndAddRange(new[] {
new GridMergedColumnSortInfo(
new[] {
colShipCountry, colShipCity, colShipRegion},
new[] {
ColumnSortOrder.Ascending, ColumnSortOrder.Descending, ColumnSortOrder.Ascending }),
new GridColumnSortInfo(colCustomerID, ColumnSortOrder.Descending)
}, 4);
gridView1.SortInfo.ClearAndAddRange( {
New GridMergedColumnSortInfo( { colShipCountry, colShipCity, colShipRegion}, { ColumnSortOrder.Ascending, ColumnSortOrder.Descending, ColumnSortOrder.Ascending }),
New GridColumnSortInfo(colCustomerID, ColumnSortOrder.Descending)
}, 4)
Set the GridColumn.SortMode property to ColumnSortMode.Custom and handle the GridView.CustomColumnGroup event to implement custom grouping based on your preferences.
The grid raises the CustomColumnGroup event for all columns with custom sort mode enabled when data is grouped by these columns.
The following example breaks order dates into four seasons and groups orders by season:
using DevExpress.XtraGrid;
using DevExpress.XtraGrid.Views.Base;
using DevExpress.XtraGrid.Views.Grid.ViewInfo;
public Form1() {
InitializeComponent();
colOrderDate.SortMode = ColumnSortMode.Custom;
colOrderDate.Group();
}
// Get the season by month
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;
}
// Implement custom grouping
void gridView1_CustomColumnGroup(object sender, CustomColumnSortEventArgs e) {
if (e.Column != colOrderDate) return;
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;
}
// Customize group row content
void gridView1_CustomDrawGroupRow(object sender, 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 = $"{season} {rowValue.Year}";
else
info.GroupText = $"{season} {rowValue.Year}/{rowValue.AddYears(1).Year}";
}
}
Imports DevExpress.XtraGrid
Imports DevExpress.XtraGrid.Views.Base
Imports DevExpress.XtraGrid.Views.Grid.ViewInfo
Public Sub New()
InitializeComponent()
colOrderDate.SortMode = ColumnSortMode.Custom
colOrderDate.Group()
End Sub
' Get the season by month
Private Function GetSeason(ByVal [date] As DateTime) As String
Dim month As Integer = [date].Month
Dim season As String = "Winter"
If month = 3 OrElse month = 4 OrElse month = 5 Then
season = "Spring"
End If
If month = 6 OrElse month = 7 OrElse month = 8 Then
season = "Summer"
End If
If month = 9 OrElse month = 10 OrElse month = 11 Then
season = "Fall"
End If
Return season
End Function
' Implement custom grouping
Private Sub gridView1_CustomColumnGroup(ByVal sender As Object, ByVal e As CustomColumnSortEventArgs)
If e.Column <> colOrderDate Then
Return
End If
Dim value1 As DateTime = CDate(e.Value1)
Dim value2 As DateTime = CDate(e.Value2)
If GetSeason(value1) = GetSeason(value2) Then
e.Result = 0
Else
e.Result = 1
End If
e.Handled = True
End Sub
' Customize group row content
Private Sub gridView1_CustomDrawGroupRow(ByVal sender As Object, ByVal e As RowObjectCustomDrawEventArgs)
Dim info As GridGroupRowInfo = TryCast(e.Info, GridGroupRowInfo)
Dim view As GridView = TryCast(sender, GridView)
If info.Column = colOrderDate Then
Dim rowValue As DateTime = CDate(view.GetGroupRowValue(info.RowHandle, info.Column))
Dim season As String = GetSeason(rowValue)
If season <> "Winter" Then
info.GroupText = $"{season} {rowValue.Year}"
Else
info.GroupText = $"{season} {rowValue.Year}/{rowValue.AddYears(1).Year}"
End If
End If
End Sub
The following API members define group row content:
|
API
|
Description
| | --- | --- | |
|
Allows you to format values in group rows for all columns.
| |
|
Allows you to format values in group rows for a column.
| |
GridOptionsBehavior.AlignGroupSummaryInGroupRow
|
Allows you to display group summaries in group rows.
|
Handle the GridView.CustomDrawGroupRow event to modify captions of specific group rows.
The following code snippet customizes the display text for group rows that correspond to the “Ship City” grouping column:
private void gridView1_CustomDrawGroupRow(object sender, DevExpress.XtraGrid.Views.Base.RowObjectCustomDrawEventArgs e) {
GridGroupRowInfo info = e.Info as GridGroupRowInfo;
if (info.Column == colShipCity)
info.GroupText = $"Shipped to {info.GroupValueText}";
}
Private Sub gridView1_CustomDrawGroupRow(ByVal sender As Object, ByVal e As DevExpress.XtraGrid.Views.Base.RowObjectCustomDrawEventArgs)
Dim info As GridGroupRowInfo = TryCast(e.Info, GridGroupRowInfo)
If info.Column = colShipCity Then
info.GroupText = $"Shipped to {info.GroupValueText}"
End If
End Sub
Group rows are identified by negative row handles. The nesting level of each group row corresponds to the position of its grouping column in the ColumnView.GroupedColumns collection.
Tip
Refer to the following help topic for more information on row handles: Access Rows.
Use the following API to identify and process group rows:
|
API
|
Description
| | --- | --- | |
|
Identifies the nesting level of a group row.
| |
|
Returns the number of immediate child rows for a group row.
| |
|
Returns the row handle of a group row’s child/nesting data row.
| |
|
Returns the row handle of a parent row.
| |
ColumnView.GetRow/ColumnView.GetDataRow
|
Methods that retrieve a DataRowView or another object that corresponds to a row.
|
The following example updates the “Price” column value for all data rows within the focused group row, including data rows in nested groups, when a button is clicked:
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);
// Update row values
view.BeginUpdate();
Discount(rowsToDiscount);
view.EndUpdate();
}
// Fill the rowsToDiscount list
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
int childHandle = view.GetChildRowHandle(groupRowHandle, i);
// If the child is a group row, add its children to the list
if(view.IsGroupRow(childHandle))
GetChildRows(view, childHandle, childRows);
else {
// The child is a data row
// Add the row to childRows if it wasn't added before
object row = view.GetRow(childHandle);
if(!childRows.Contains(row))
childRows.Add(row);
}
}
}
// Update Price column values in 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;
}
}
Imports DevExpress.XtraGrid.Views.Grid
' ...
Private Sub ButtonDiscount_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles ButtonDiscount.Click
Dim View As GridView = GridView1
Dim rowHandle As Integer = View.FocusedRowHandle
Dim rowsToDiscount As ArrayList = New ArrayList
' Get related data rows
If View.IsGroupRow(rowHandle) Then
GetChildRows(View, rowHandle, rowsToDiscount)
End If
' Change row values
View.BeginUpdate()
Discount(rowsToDiscount)
View.EndUpdate()
End Sub
' Fill the rowsToDiscount list
Public Sub GetChildRows(ByVal View As GridView, ByVal groupRowHandle As Integer, _
ByVal childRows As ArrayList)
If Not View.IsGroupRow(groupRowHandle) Then Return
' Get the number of immediate children
Dim childCount As Integer = View.GetChildRowCount(groupRowHandle)
Dim i As Integer
For i = 0 To childCount - 1
' Get the handle of a child row
Dim childHandle As Integer = View.GetChildRowHandle(groupRowHandle, i)
' If the child is a group row, add its children to the list
If View.IsGroupRow(childHandle) Then
GetChildRows(View, childHandle, childRows)
Else
' The child is a data row
' Add the row to childRows if it was not added before
Dim row As Object = View.GetRow(childHandle)
If Not childRows.Contains(row) Then childRows.Add(row)
End If
Next
End Sub
' Update Price column values in specified rows
Public Sub Discount(ByVal rows As ArrayList)
Dim i As Integer
For i = 0 To rows.Count - 1
Dim row As DataRow = CType(rows(i), DataRowView).Row
Dim oldValue As Decimal = row("Price")
row("Price") = oldValue * 0.95
Next
End Sub
Use the following API to expand and collapse group rows:
|
API
|
Description
| | --- | --- | |
|
Gets whether the group row is expanded.
| |
|
Expands the specified group row.
| |
|
Collapses the specified group row.
| |
|
Expands or collapses the specified group row.
| |
|
Scrolls the View to the specified row and focuses this row. Expands the row’s parent group.
| |
|
Scrolls the View to display the required row. If the row belongs to a group, this group expands.
|
Expand/collapse operations raise the following events:
|
API
|
Description
| | --- | --- | |
|
Fires when a group row is about to be expanded and allows you to cancel the expand operation.
| |
|
Fires when a group row is about to be collapsed and allows you to cancel the collapse operation.
| |
|
Fires after a group row is expanded.
| |
|
Fires after a group row is collapsed.
|
The following code snippet displays all data rows where the “InStock” column value is true:
using DevExpress.XtraGrid.Views.Grid;
//...
GridView View = gridView1;
int rowHandle = -1;
do {
rowHandle = View.LocateByValue(rowHandle + 1, View.Columns["IsInStock"], true);
View.MakeRowVisible(rowHandle, false);
} while (rowHandle != GridControl.InvalidRowHandle);
Imports DevExpress.XtraGrid.Views.Grid
'...
Dim View As GridView = GridView1
Dim rowHandle As Integer = -1
Do
rowHandle = View.LocateByValue(rowHandle + 1, View.Columns("IsInStock"), True)
View.MakeRowVisible(rowHandle, False)
Loop Until rowHandle = GridControl.InvalidRowHandle
See Also
Tutorial: Custom Grouping Algorithms