Group Data in Blazor Grid
- 17 minutes to read
The Grid can group data against one or more columns:
- Users can drag column headers between the header panel and the group panel.
- You can use Grid API to group data in code.
The Grid uses group rows to organize data rows into a tree when data grouping is applied.
Every time a grid component groups data, it executes the following steps:
Sorts data by the column. Note that a grouped column is always sorted.
At this step, you can implement custom sort logic.
Compares adjacent row values. If values are equal, the Grid puts them in the same group. If the values are different, the second value starts a new group.
At this step, you can implement custom row value comparison logic (define custom group intervals).
Hides the grouping column and displays its header in the group panel.
You can set the ShowGroupedColumns property to
true
to display grouped columns in the grid.Shows collapsed group rows.
You can set the AutoExpandAllGroupRows property to
true
to expand all group rows.
Group Data in the UI
Set the ShowGroupPanel property to true
to display the group panel.
The following user operations are available:
- Drag and drop a column header onto the group panel to group data against the column.
- Drag headers within this panel to change group order.
- Drag a column header from the group panel back to the column header panel to ungroup data.
You can use the following properties to prohibit end-user data grouping operations:
- DxGrid.AllowGroup
- Specifies whether users can group grid data.
- DxGridDataColumn.AllowGroup
- Specifies whether users can group grid data by the current column.
<DxGrid Data="Data" ShowGroupPanel="true" >
<Columns>
<DxGridDataColumn FieldName="ContactName" AllowGroup="false"/>
<DxGridDataColumn FieldName="CompanyName" />
<DxGridDataColumn FieldName="City" />
<DxGridDataColumn FieldName="Region" />
<DxGridDataColumn FieldName="Country" />
</Columns>
</DxGrid>
Group Data in Code
Group Data
Use one of the following API members to group grid data by a column:
Use a column’s GroupIndex property to specify whether the column takes part in grouping and at which level.
You can use this property to initially group rows or to change grouping at runtime. Note that you need to enclose your code between BeginUpdate and EndUpdate method calls to change values of Grid component parameters outside the Grid component markup. Otherwise, an exception occurs.
<!-- Specifies initial group settings --> <DxGridDataColumn FieldName="Country" GroupIndex="0" />
// Changes a group index at runtime Grid.BeginUpdate(); Grid.GetDataColumns().First(i => i.FieldName == "Country").GroupIndex = 1; Grid.EndUpdate();
Call the GroupBy method.
Grid.GroupBy("Country", 0); Grid.GroupBy("City");
Ungroup Data
You can ungroup grid data by a column in the following ways:
Set the column’s GroupIndex property to
-1
.
Note that you need to enclose your code between BeginUpdate and EndUpdate method calls to change values of Grid component parameters outside the Grid component markup. Otherwise, an exception occurs.Call the GroupBy(String, Int32) method and pass
-1
as thegroupIndex
parameter.
Call the GetGroupCount() method to get the number of grouped columns. Refer to the following section to learn how to get a group column collection: Get Grouped Columns.
Expand and Collapse Group Rows
When data is grouped by a column, the Grid displays collapsed group rows. Set the AutoExpandAllGroupRows property to true
to expand all group rows automatically when the grid loads data or users interact with the grid, for instance, sorts or filters data.
Users can click group buttons to expand and collapse group rows. Users can also focus a group row and press the Left Arrow or Right Arrow key to expand or collapse this row. To change a group row’s state in code, call the following methods:
- ExpandAllGroupRows()
- Expands all group rows.
- ExpandGroupRow(Int32, Boolean)
- Expands a group row with the specified visible index.
- CollapseAllGroupRows()
- Collapses all group rows.
- CollapseGroupRow(Int32, Boolean)
- Collapses a group row with the specified visible index.
To determine a group row’s expanded state, call the IsGroupRowExpanded(Int32) method.
Group Data by Display Text
Set a column’s GroupInterval property to DisplayText
to group grid rows by column display text. This scenario can be useful when you specify custom display text for column cells (see DisplayFormat property and CustomizeCellDisplayText event descriptions).
Note
The Grid does not support grouping by display text when you use a Server Mode data source or GridDevExtremeDataSource.
@inject WeatherForecastService ForecastService
<DxGrid Data="@forecasts" ShowGroupPanel="true" CustomizeCellDisplayText="Grid_CustomizeCellDisplayText">
<Columns>
<DxGridDataColumn FieldName="Date" DisplayFormat="D"
GroupInterval="GridColumnGroupInterval.DisplayText" />
<DxGridDataColumn FieldName="TemperatureC" TextAlignment="GridTextAlignment.Left" Caption="Forecast"
GroupInterval="GridColumnGroupInterval.DisplayText"/>
<DxGridDataColumn FieldName="CloudCover" />
</Columns>
</DxGrid>
@code {
object forecasts;
protected override void OnInitialized() {
forecasts = ForecastService.GetForecast();
}
void Grid_CustomizeCellDisplayText(GridCustomizeCellDisplayTextEventArgs e) {
if (e.FieldName == "TemperatureC") {
int val = Convert.ToInt32(e.Value);
if (val < 15)
e.DisplayText = "Cold";
else if (val < 25)
e.DisplayText = "Warm";
else
e.DisplayText = "Hot";
}
}
}
Interval Grouping
Adjacent rows form a single group if they contain matching values in a grouping column.
If you group data by a date/time column, the grid only compares the date portion. Rows that contain matching dates form a single group (regardless of time).
You can group data rows by value intervals. The Grid implements a set or predefined intervals and allows you to create custom intervals. Use the GroupInterval property to apply the following predefined interval grouping:
DateMonth
- The grid only compares the month and year portion of date/time values.
DateYear
- The grid only compares the year portion of date/time values.
DateRange
- The grid groups date/time values into intervals used by popular email clients (Last Month, Last Week, Yesterday, Today, Tomorrow, Next Week, and so on).
Alphabetical
- The grid compares only the first character of string values.
Note
The Grid does not support interval grouping when you use GridDevExtremeDataSource.
<DxGrid Data="Data" ShowGroupedColumns="true">
<Columns>
<DxGridDataColumn FieldName="CompanyName"
GroupIndex="0"
GroupInterval="GridColumnGroupInterval.Alphabetical" />
<DxGridDataColumn FieldName="ContactName" />
<DxGridDataColumn FieldName="City" />
<DxGridDataColumn FieldName="Country" />
</Columns>
</DxGrid>
Custom Group Intervals
To group rows by custom intervals, follow the steps below:
- Set a column’s GroupInterval property to
Custom
. - Handle the CustomGroup event that fires for every pair of adjacent row values. Use the event argument’s SameGroup property to specify whether the processed rows belong to the same group.
- (optional) When you implement custom group intervals, the Grid displays the value of the first row in the group as a group row value. Handle the CustomizeGroupValueDisplayText event to specify a custom group row value. For more information, refer to the following section: Customize Group Row Content and Appearance.
Note
The Grid does not support custom group intervals when you use Server Mode data source or GridDevExtremeDataSource.
The following code snippet implements custom group intervals for the Unit Price column. Data are grouped for the following intervals: $0.00 - $10.00, $10.00 - $20.00, etc.
<DxGrid Data="GridDataSource"
ShowGroupPanel="true"
CustomGroup="Grid_CustomGroup"
CustomizeGroupValueDisplayText="Grid_CustomizeGroupValueDisplayText">
<Columns>
<DxGridDataColumn FieldName="ProductName" />
<DxGridDataColumn FieldName="Country" />
<DxGridDataColumn FieldName="OrderDate" DisplayFormat="d" />
<DxGridDataColumn FieldName="UnitPrice" DisplayFormat="c"
GroupIndex="0" GroupInterval="GridColumnGroupInterval.Custom" />
<DxGridDataColumn FieldName="Quantity" />
</Columns>
</DxGrid>
@code {
// ...
void Grid_CustomGroup(GridCustomGroupEventArgs e) {
if(e.FieldName == "UnitPrice") {
e.SameGroup = Grid_CompareColumnValues(e.Value1, e.Value2) == 0;
e.Handled = true;
}
}
int Grid_CompareColumnValues(object value1, object value2) {
double val1 = Math.Floor(Convert.ToDouble(value1) / 10);
double val2 = Math.Floor(Convert.ToDouble(value2) / 10);
var res = System.Collections.Comparer.Default.Compare(val1, val2);
if(res < 0)
res = -1;
else if(res > 0)
res = 1;
if(res == 0 || (val1 > 9 && val2 > 9))
res = 0;
return res;
}
void Grid_CustomizeGroupValueDisplayText(GridCustomizeGroupValueDisplayTextEventArgs e) {
if(e.FieldName == "UnitPrice") {
double val = Math.Floor(Convert.ToDouble(e.Value) / 10);
string displayText = string.Format("{0:c} - {1:c} ", val * 10, (val + 1) * 10);
if(val > 9)
displayText = string.Format(">= {0:c} ", 100);
e.DisplayText = displayText;
}
}
}
Custom Grouping
The Grid allows you to apply a custom grouping algorithm to its data. Follow the steps below to enable this functionality:
- Set a column’s SortMode property to
Custom
and handle the CustomSort event to implement custom data sorting. - Set the column’s GroupInterval property to
Custom
and handle the CustomGroup event to implement custom group intervals. - (optional) Handle the CustomizeGroupValueDisplayText event to specify custom group value display text.
- (optional) Implement the GroupRowTemplate template to specify custom group row content.
Note
The Grid does not support custom grouping when you use Server Mode data source or GridDevExtremeDataSource.
The following code snippet groups countries by population.
<DxGrid Data="countryInfo" ShowGroupPanel="true" ShowGroupedColumns="true"
CustomSort="Grid_CustomSort"
CustomGroup="Grid_CustomGroup"
CustomizeGroupValueDisplayText="Grid_CustomizeGroupValueDisplayText" >
<Columns>
<DxGridDataColumn FieldName="Country" SortMode="GridColumnSortMode.Custom"
GroupInterval="GridColumnGroupInterval.Custom">
<GroupRowTemplate>
Countries with a population of @context.GroupValueDisplayText people
</GroupRowTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="Population" />
</Columns>
</DxGrid>
@code {
CountryInfo[]? countryInfo;
protected override async Task OnInitializedAsync() {
countryInfo = await CountryInfo.GetData();
}
// Sorts the Country column by values of the Population column
void Grid_CustomSort(GridCustomSortEventArgs e) {
if(e.FieldName == "Country") {
var population1 = (int)e.GetRow1Value("Population");
var population2 = (int)e.GetRow2Value("Population");
e.Result = population1.CompareTo(population2);
e.Handled = true;
}
}
// Specifies intervals for grouping
void Grid_CustomGroup(GridCustomGroupEventArgs e) {
if(e.FieldName == "Country") {
var val1Exponent = e.GetRow1Value("Population").ToString().Length;
var val2Exponent = e.GetRow2Value("Population").ToString().Length;
e.SameGroup = val1Exponent == val2Exponent;
e.Handled = true;
}
}
// Customizes a group row value
void Grid_CustomizeGroupValueDisplayText(GridCustomizeGroupValueDisplayTextEventArgs e) {
if(e.FieldName == "Country") {
var valueExponent = e.GetRowValue("Population").ToString().Length;
var minGroupValue = Math.Pow(10, valueExponent-1);
var maxGroupValue = Math.Pow(10, valueExponent)-1;
e.DisplayText = string.Format("Countries with a population of {0:n0} to {1:n0} people",minGroupValue,maxGroupValue);
if ((int)e.GetRowValue("Population") < 1000)
e.DisplayText = "Countries with a population less than 1000 people";
if ((int)e.GetRowValue("Population") > 1000000000)
e.DisplayText = "Countries with a population more than 1,000,000,000 people";
}
}
}
Customize Group Row Content and Appearance
Group row text consists of the following elements:
{column}: {value} ({summary}, {summary})
The Grid allows you to customize display text of the specified elements or create templates to modify group row content (for instance, hide any part).
{column}
- The grouping column’s header text. The Grid specifies column header text based on the FieldName property value. The component adds spaces between words if a field name uses the CamelCase naming convention. You can set the Caption property to specify the column header text explicitly.
{value}
- The value’s display text. Handle the CustomizeGroupValueDisplayText event to customize a group value’s display text.
{summary}
- A summary item’s display text. You can use the ValueDisplayFormat property to specify a display format for the summary item value. The DisplayText property allows you to specify the display text pattern for the summary item.
Customize Group Row Appearance
Handle the CustomizeElement event to customize group row appearance. Compare the event argument’s e.ElementType property with the GroupRow
or GroupCell
value to determine whether the processed element is a group row or cell.
void Grid_CustomizeElement(GridCustomizeElementEventArgs e) {
if(e.ElementType == GridElementType.GroupRow)
e.CssClass = "custom-group-row-class";
}
Create a Group Row Template
Use the following properties to implement custom group row content:
- DxGrid.DataColumnGroupRowTemplate
- Specifies a common template used to display all group rows in the Grid.
- DxGridDataColumn.GroupRowTemplate
- Specifies a template used to display group rows when the Grid is grouped by this column.
<DxGrid Data="Data" ShowGroupPanel="true">
<Columns>
<DxGridDataColumn FieldName="CompanyName" />
<DxGridDataColumn FieldName="Country" GroupIndex="0">
<GroupRowTemplate>
<text>@context.ColumnCaption: @context.GroupValue</text>
@{
var summaryItems = context.Grid.GetGroupSummaryItems();
if(summaryItems.Any()) {
<text> (</text>
foreach(var i in summaryItems) {
if(i != summaryItems.First()) {
<text>, </text>
}
@context.Grid.GetGroupSummaryLabel(i, context.VisibleIndex)
<text>: </text>
<b>@context.Grid.GetGroupSummaryFormattedValue(i, context.VisibleIndex)</b>
}
<text>)</text>
}
}
</GroupRowTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="City" />
<DxGridDataColumn FieldName="UnitPrice" DisplayFormat="c" />
<DxGridDataColumn FieldName="Quantity" />
<DxGridDataColumn FieldName="Total"
UnboundType="GridUnboundColumnType.Decimal"
UnboundExpression="[UnitPrice] * [Quantity]"
DisplayFormat="c" />
</Columns>
<GroupSummary>
<DxGridSummaryItem SummaryType="GridSummaryItemType.Sum" FieldName="Total" />
<DxGridSummaryItem SummaryType="GridSummaryItemType.Count" FieldName="CompanyName" />
</GroupSummary>
</DxGrid>
Group Summary
Group summaries are calculated across all rows within a group and displayed in the group row or group footer. To create group summaries, declare DxGridSummaryItem objects in the GroupSummary template.
<DxGrid Data="Data" ShowGroupPanel="true">
<Columns>
<DxGridDataColumn FieldName="Country" GroupIndex="0" />
<DxGridDataColumn FieldName="City" GroupIndex="1" />
<DxGridDataColumn FieldName="CompanyName" />
<DxGridDataColumn FieldName="UnitPrice" DisplayFormat="c" />
<DxGridDataColumn FieldName="Quantity" />
<DxGridDataColumn FieldName="Total" DisplayFormat="c" UnboundType="GridUnboundColumnType.Decimal"
UnboundExpression="[UnitPrice] * [Quantity]" />
</Columns>
<GroupSummary>
<DxGridSummaryItem SummaryType="GridSummaryItemType.Count" FieldName="CompanyName" />
<DxGridSummaryItem SummaryType="GridSummaryItemType.Sum" FieldName="Total" />
</GroupSummary>
</DxGrid>
For more information about group summaries, refer to the following topic: Summary in Blazor Grid.
Limitations
The Grid has the following specifics and limitations when you use GridDevExtremeDataSource:
- Interval grouping, custom grouping, and grouping by display text are not supported.
- A data grouping operation cancels any “select all” or “deselect all” operation in progress.
The Grid has the following specifics and limitations when you use a Server Mode data source:
- Grouping by display text is not supported.
- Custom grouping is not supported.
- A data grouping operation cancels any “select all” or “deselect all” operation in progress.
Related API
This section contains a comprehensive grouping-related API reference.
Grid API member | Type | Description |
---|---|---|
AllowGroup | Property | Specifies whether users can group grid data. |
AutoExpandAllGroupRows | Property | Specifies whether to expand all group rows automatically when the grid loads data or users interact with the grid. |
CollapseAllGroupRows() | Method | Collapses all group rows. |
CollapseGroupRow(Int32, Boolean) | Method | Collapses a group row with the specified visible index. |
ColumnGroupFooterTemplate | Property | Specifies a common template for all group footer cells in the Grid. |
CustomGroup | Event | Enables you to implement custom logic used to group data in the grid. |
CustomizeGroupValueDisplayText | Event | Allows you to customize the group value’s display text. |
DataColumnGroupRowTemplate | Property | Specifies a common template used to display all group rows in the Grid. |
ExpandGroupRow(Int32, Boolean) | Method | Expands a group row with the specified visible index. |
GetGroupCount() | Method | Gets the number of grouped columns. |
GetGroupSummaryDisplayText(IGridSummaryItem, Int32) | Method | Gets a group summary item’s display text. |
GetGroupSummaryFormattedValue(IGridSummaryItem, Int32) | Method | Gets a group summary item’s formatted value. |
GetGroupSummaryItems() | Method | Gets the collection of group summary items. |
GetGroupSummaryLabel(IGridSummaryItem, Int32) | Method | Gets the name of a group summary‘s function name. |
GetGroupSummaryValue(IGridSummaryItem, Int32) | Method | Gets a group summary item’s value. |
GroupBy | Method | Groups data by values of the specified column and inserts the grouped column in the specified position between other grouped columns. |
GroupFooterDisplayMode | Property | Specifies when to display group footers in the Grid. |
GetRowLevel(Int32) | Method | Gets the nesting level of the processed row. |
GroupSummary | Property | Contains group summary items. |
IsGroupRow(Int32) | Method | Specifies whether the specified row is a group row. |
IsGroupRowExpanded(Int32) | Method | Specifies whether the specified group row is expanded. |
ShowGroupedColumns | Property | Specifies whether to display grouped columns with other columns in the grid’s data area. |
ShowGroupPanel | Property | Specifies whether to show the Group Panel. |
Column API member | Type | Description |
---|---|---|
AllowGroup | Property | Specifies whether users can group data by this column. |
GroupFooterTemplate | Property | Specifies a template for the column’s group footer cell. |
GroupIndex | Property | Specifies the column’s index among grouped columns. |
GroupIndexChanged | Event | Fires when the column’s group index changes. |
GroupInterval | Property | Specifies how to group data rows. |
GroupRowTemplate | Property | Specifies a template used to display group rows when the Grid is grouped by this column. |
Task-Based Examples
This section contains code samples that involve data grouping functionality.
Get Grouped Columns
The grouped columns are always sorted and have the highest sort priority. Thereby, the Grid maintains grouped columns at the beginning of the collection of sorted columns. Use GetSortedColumns() and GetGroupCount() methods to get a collection of the grouped columns.
IEnumerable<IGridDataColumn> groupedColumns = Grid.GetSortedColumns().Take(grid.GetGroupCount());
Show Grouped Column in Grid
The Grid hides grouped columns and displays their headers in the group panel. Set the ShowGroupedColumns property to true
to display grouped columns in the grid.
<DxGrid Data="countryInfo" ShowGroupPanel="true" ShowGroupedColumns="true" >
<!-- ... -->
</DxGrid>
Sort Groups by Another Column’s Values
When you group data by a field, the Grid sorts all data by this field as well. You can handle the CustomSort event to implement custom sorting logic for a column.
In the following code snippet, the Group column values are sorted according to ImportanceValue field values.
<DxGrid Data="Data" ShowGroupPanel="true" CustomSort="Grid_CustomSort">
<Columns>
<DxGridDataColumn FieldName="GroupName" Caption="Group" GroupIndex="0"
SortMode="GridColumnSortMode.Custom" />
<DxGridDataColumn FieldName="Name" SortIndex="1" />
<DxGridDataColumn FieldName="Value" />
</Columns>
</DxGrid>
@code {
object Data { get; set; }
protected override void OnInitialized() {
Data = new List<MyData> {
new MyData { ImportanceValue = 1, GroupName = "High", Name = "Item1", Value = "Value1" },
new MyData { ImportanceValue = 3, GroupName = "Low", Name = "Item5", Value = "Value5" },
new MyData { ImportanceValue = 1, GroupName = "High", Name = "Item6", Value = "Value6" },
new MyData { ImportanceValue = 2, GroupName = "Normal", Name = "Item4", Value = "Value4" },
new MyData { ImportanceValue = 2, GroupName = "Normal", Name = "Item2", Value = "Value2" },
new MyData { ImportanceValue = 3, GroupName = "Low", Name = "Item8", Value = "Value8" },
new MyData { ImportanceValue = 1, GroupName = "High", Name = "Item3", Value = "Value3" },
new MyData { ImportanceValue = 2, GroupName = "Normal", Name = "Item7", Value = "Value7" }
};
}
void Grid_CustomSort(GridCustomSortEventArgs e) {
if(e.FieldName == "GroupName") {
var val1 = (int)e.GetRow1Value("ImportanceValue");
var val2 = (int)e.GetRow2Value("ImportanceValue");
e.Result = val1.CompareTo(val2);
e.Handled = true;
}
}
class MyData {
public int ImportanceValue { get; set; }
public string GroupName { get; set; }
public string Name { get; set; }
public string Value { get; set; }
}
}
Select Items in a Group
To allow users to select and deselect all rows in a group, implement the DataColumnGroupRowTemplate template. Place the DxCheckBox<T> component in the template and handle checked state changes.
You can see a complete code sample in the following GitHub example: Select and Deselect All Rows in a Group.
Customize Date Format in Group Rows
Handle the CustomizeGroupValueDisplayText event to format a group value in a group row.
void OnCustomizeGroupValueDisplayText(GridCustomizeGroupValueDisplayTextEventArgs e) {
if(e.FieldName == "OrderDate") {
e.DisplayText = string.Format("{0:D} ", e.Value);
}
}
Get Rows in a Group
You can filter a data source based on a group value to get a list of data items contained in the group.
private Customer[]? customers;
public static List<object> GetGroupDataItems(object groupValue) {
var children = customers.Where(e => e.Country == groupValue.ToString()).ToList();
return children;
}
Alternatively, you can iterate manually through grid rows.
public static List<object> GetGroupDataItems(IGrid grid, int visibleIndex) {
var result = new List<object>();
var rowLevel = grid.GetRowLevel(visibleIndex);
grid.ExpandGroupRow(visibleIndex, true);
for(var i = visibleIndex + 1; i < grid.GetVisibleRowCount(); i++) {
if(grid.GetRowLevel(i) <= rowLevel)
break;
if(!grid.IsGroupRow(i))
result.Add(grid.GetDataItem(i));
}
return result;
}
Hide Group Header Field Name
Use the GroupRowTemplate property to display the required value without the name of the column.
<DxGridDataColumn FieldName="Summary" GroupIndex="0" >
<GroupRowTemplate>@context.GroupValue</GroupRowTemplate>
</DxGridDataColumn>
Expand First-Level Groups Only
To expand first-level groups only, follow the steps below:
- Iterate through the grid’s visible rows.
- Call the GetRowLevel(Int32) method to determine the nesting level of a row.
- Call the ExpandGroupRow(Int32, Boolean) method to expand rows of the first level.
static void ExpandFirstLevelsOnly(IGrid grid) {
grid.BeginUpdate();
grid.CollapseAllGroupRows();
for(var i = grid.GetVisibleRowCount() - 1; i >= 0; i--){
if(grid.GetRowLevel(i) == 0)
grid.ExpandGroupRow(i);
}
grid.EndUpdate();
}