blazor-404433-components-grid-data-shaping-group-data.md
The Grid can group data against one or more columns:
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.
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.
Hides the grouping column and displays its header in the group panel.
Shows collapsed group rows.
Set the ShowGroupPanel property to true to display the group panel.
The following user operations are available:
You can use the following properties to prohibit end-user data grouping operations:
DxGrid.AllowGroupSpecifies whether users can group grid data.DxGridDataColumn.AllowGroupSpecifies 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>
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.
Call the GroupBy method.
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 the groupIndex 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.
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.
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";
}
}
}
using System;
public class WeatherForecast {
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public double TemperatureF => Math.Round((TemperatureC * 1.8 + 32), 2);
public string Forecast { get; set; }
public string CloudCover { get; set; }
public bool Precipitation { get; set; }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
public class WeatherForecastService {
private List<WeatherForecast> Forecast { get; set; }
private static string[] CloudCover = new[] {
"Sunny", "Partly cloudy", "Cloudy", "Storm"
};
Tuple<int, string>[] ConditionsForForecast = new Tuple<int, string>[] {
Tuple.Create( 22 , "Hot"),
Tuple.Create( 13 , "Warm"),
Tuple.Create( 0 , "Cold"),
Tuple.Create( -10 , "Freezing")
};
public WeatherForecastService() {
Forecast = CreateForecast();
}
private List<WeatherForecast> CreateForecast() {
var rng = new Random();
DateTime startDate = DateTime.Now;
return Enumerable.Range(1, 15).Select(index => {
var temperatureC = rng.Next(-10, 30);
return new WeatherForecast {
Date = startDate.AddDays(index),
TemperatureC = temperatureC,
CloudCover = CloudCover[rng.Next(0, 4)],
Precipitation = Convert.ToBoolean(rng.Next(0, 2)),
Forecast = ConditionsForForecast.First(c => c.Item1 <= temperatureC).Item2
};
}).ToList();
}
public IEnumerable<WeatherForecast> GetForecast() {
return Forecast.ToArray();
}
// ...
}
// ...
builder.Services.AddSingleton<WeatherForecastService>();
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:
DateMonthThe grid only compares the month and year portion of date/time values.DateYearThe grid only compares the year portion of date/time values.DateRangeThe grid groups date/time values into intervals used by popular email clients (Last Month, Last Week, Yesterday, Today, Tomorrow, Next Week, and so on).AlphabeticalThe 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>
The Grid component supports custom data grouping. Custom data groups allow you to merge data into custom intervals or combine similar values into a single entry. Follow the steps below to enable this functionality:
Custom and handle the CustomSort event. In the event handler, compare column values to define the associated order.Custom and handle the CustomGroup event. In the event handler, compare column values to define whether they belong to the same group.Note
The Grid does not support custom grouping when you use Server Mode data source or GridDevExtremeDataSource.
The following code snippet groups the Unit Price column by custom range values: $0.00-$10.00, $10.00-$20.00, etc.
<DxGrid Data="@Data"
ShowGroupPanel="true"
CustomGroup="Grid_CustomGroup"
CustomSort="Grid_CustomSort"
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" SortMode="GridColumnSortMode.Custom" />
<DxGridDataColumn FieldName="Quantity" />
</Columns>
<TotalSummary>
<DxGridSummaryItem SummaryType="GridSummaryItemType.Count" FieldName="ProductName" />
</TotalSummary>
<GroupSummary>
<DxGridSummaryItem SummaryType="GridSummaryItemType.Count" FieldName="UnitPrice" />
</GroupSummary>
</DxGrid>
@code {
// ...
void Grid_CustomGroup(GridCustomGroupEventArgs e) {
if(e.FieldName == "UnitPrice") {
e.SameGroup = Grid_CompareColumnValues(e.Value1, e.Value2) == 0;
e.Handled = true;
}
}
void Grid_CustomSort(GridCustomSortEventArgs e) {
if (e.FieldName == "UnitPrice") {
e.Result = Grid_CompareColumnValues(e.Value1, e.Value2);
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;
}
}
}
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.
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";
}
Use the following properties to implement custom group row content:
DxGrid.DataColumnGroupRowTemplateSpecifies a common template used to display all group rows in the Grid.DxGridDataColumn.GroupRowTemplateSpecifies 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 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>
Run Demo: Group SummaryRun Demo: Group Footer Summary
For additional information about group summaries, refer to the following topic: Summary in Blazor Grid.
The Grid has the following specifics and limitations when you use GridDevExtremeDataSource:
The Grid has the following specifics and limitations when you use a Server Mode data source:
This section contains a comprehensive grouping-related API reference.
Show 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. |
This section contains code samples that involve data grouping functionality.
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());
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>
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; }
}
}
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.
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);
}
}
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;
}
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>
To expand first-level groups only, follow the steps below:
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();
}