DxGridDataColumn.GroupInterval Property
Specifies how to group data rows.
Namespace : DevExpress.Blazor
Assembly :
DevExpress.Blazor.v25.1.dll
NuGet Package :
DevExpress.Blazor
Declaration
[DefaultValue(GridColumnGroupInterval.Default)]
[Parameter]
public GridColumnGroupInterval GroupInterval { get; set; }
Property Value
Available values:
Name
Description
Default
For date/time columns, this option is the same as the Date
option. For non date/time columns, this option is the same as the Value
option.
Value
Rows are grouped by the column values.
Date
For date/time columns, rows are grouped by the date part of their values. The time part is ignored.
DateMonth
For date/time columns, rows are grouped by the month part of their values.
DateYear
For date/time columns, rows are grouped by the year part of their values.
DateRange
For date/time columns, rows are combined into the following non-overlapping groups according to their date value as compared with today’s date: “Beyond Next Month”, “Next Month”, “Later this Month”, “Three Weeks Away”, “Two Weeks Away”, “Next Week”, “Today”, “Tomorrow”, “Yesterday”, “Sunday”, “Monday”, “Tuesday”, “Wednesday”, “Thursday”, “Friday”, “Saturday”, “Last Week”, “Two Weeks Ago”, “Three Weeks Ago”, “Earlier this Month”, “Last Month”, “Older”.
Alphabetical
Rows are grouped by the character that the column values start with.
DisplayText
Rows are grouped by the column values’ display text .
Custom
Custom logic is used to group grid data.
The GroupInterval
property specifies how to group data rows. For example, you can group date-time values by year, month or date, or you can group text values by display text or against individual characters.
@using Microsoft.EntityFrameworkCore
@inject IDbContextFactory<NorthwindContext> NorthwindContextFactory
@implements IDisposable
<DxGrid Data="GridDataSource"
ShowGroupPanel="true"
CustomizeCellDisplayText="OnCustomizeCellDisplayText">
<Columns>
<DxGridDataColumn FieldName="OrderDate"
DisplayFormat="d"
GroupIndex="0"
GroupInterval="GridColumnGroupInterval.DateMonth"/>
<DxGridDataColumn FieldName="Customer"
SortMode="GridColumnSortMode.DisplayText"
GroupIndex="1"
GroupInterval="GridColumnGroupInterval.DisplayText" />
<DxGridDataColumn FieldName="Freight"
DisplayFormat="n2" />
</Columns>
</DxGrid>
@code {
object GridDataSource { get; set; }
NorthwindContext Northwind { get; set; }
protected override void OnInitialized() {
Northwind = NorthwindContextFactory.CreateDbContext();
GridDataSource = Northwind.Orders
.Include(i => i.Customer)
.Include(i => i.OrderDetails)
.Include(i => i.ShipViaNavigation)
.ToList();
}
void OnCustomizeCellDisplayText(GridCustomizeCellDisplayTextEventArgs e) {
if (e.FieldName == "Customer")
{
var customer = (Customer)e.Value;
e.DisplayText = $"{customer.CompanyName} ({customer.Country}, {customer.City})";
}
}
public void Dispose() {
Northwind?.Dispose();
}
}
using Microsoft.EntityFrameworkCore;
#nullable disable
namespace Grid.Northwind {
public partial class NorthwindContext : DbContext {
public NorthwindContext(DbContextOptions<NorthwindContext> options)
: base(options) {
}
public virtual DbSet<Category> Categories { get; set; }
public virtual DbSet<Customer> Customers { get; set; }
public virtual DbSet<Invoice> Invoices { get; set; }
public virtual DbSet<Order> Orders { get; set; }
public virtual DbSet<OrderDetail> OrderDetails { get; set; }
public virtual DbSet<Product> Products { get; set; }
public virtual DbSet<Shipper> Shippers { get; set; }
public virtual DbSet<Supplier> Suppliers { get; set; }
public virtual DbSet<Employee> Employees { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
if(!optionsBuilder.IsConfigured) {
optionsBuilder.UseSqlServer("Server=.\\sqlexpress;Database=Northwind;Integrated Security=true");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.HasAnnotation("Relational:Collation", "SQL_Latin1_General_CP1_CI_AS");
modelBuilder.Entity<Category>(entity => {
entity.HasIndex(e => e.CategoryName, "CategoryName");
entity.Property(e => e.CategoryId).HasColumnName("CategoryID");
entity.Property(e => e.CategoryName)
.IsRequired()
.HasMaxLength(15);
entity.Property(e => e.Description).HasColumnType("ntext");
entity.Property(e => e.Picture).HasColumnType("image");
});
modelBuilder.Entity<Customer>(entity => {
entity.HasIndex(e => e.City, "City");
entity.HasIndex(e => e.CompanyName, "CompanyName");
entity.HasIndex(e => e.PostalCode, "PostalCode");
entity.HasIndex(e => e.Region, "Region");
entity.Property(e => e.CustomerId)
.HasMaxLength(5)
.HasColumnName("CustomerID")
.IsFixedLength(true);
entity.Property(e => e.Address).HasMaxLength(60);
entity.Property(e => e.City).HasMaxLength(15);
entity.Property(e => e.CompanyName)
.IsRequired()
.HasMaxLength(40);
entity.Property(e => e.ContactName).HasMaxLength(30);
entity.Property(e => e.ContactTitle).HasMaxLength(30);
entity.Property(e => e.Country).HasMaxLength(15);
entity.Property(e => e.Fax).HasMaxLength(24);
entity.Property(e => e.Phone).HasMaxLength(24);
entity.Property(e => e.PostalCode).HasMaxLength(10);
entity.Property(e => e.Region).HasMaxLength(15);
});
modelBuilder.Entity<Invoice>(entity => {
entity.HasNoKey();
entity.ToView("Invoices");
entity.Property(e => e.Address).HasMaxLength(60);
entity.Property(e => e.City).HasMaxLength(15);
entity.Property(e => e.Country).HasMaxLength(15);
entity.Property(e => e.CustomerId)
.HasMaxLength(5)
.HasColumnName("CustomerID")
.IsFixedLength(true);
entity.Property(e => e.CustomerName)
.IsRequired()
.HasMaxLength(40);
entity.Property(e => e.ExtendedPrice).HasColumnType("money");
entity.Property(e => e.Freight).HasColumnType("money");
entity.Property(e => e.OrderDate).HasColumnType("datetime");
entity.Property(e => e.OrderId).HasColumnName("OrderID");
entity.Property(e => e.PostalCode).HasMaxLength(10);
entity.Property(e => e.ProductId).HasColumnName("ProductID");
entity.Property(e => e.ProductName)
.IsRequired()
.HasMaxLength(40);
entity.Property(e => e.Region).HasMaxLength(15);
entity.Property(e => e.RequiredDate).HasColumnType("datetime");
entity.Property(e => e.Salesperson)
.IsRequired()
.HasMaxLength(31);
entity.Property(e => e.ShipAddress).HasMaxLength(60);
entity.Property(e => e.ShipCity).HasMaxLength(15);
entity.Property(e => e.ShipCountry).HasMaxLength(15);
entity.Property(e => e.ShipName).HasMaxLength(40);
entity.Property(e => e.ShipPostalCode).HasMaxLength(10);
entity.Property(e => e.ShipRegion).HasMaxLength(15);
entity.Property(e => e.ShippedDate).HasColumnType("datetime");
entity.Property(e => e.ShipperName)
.IsRequired()
.HasMaxLength(40);
entity.Property(e => e.UnitPrice).HasColumnType("money");
});
modelBuilder.Entity<Order>(entity => {
entity.HasIndex(e => e.CustomerId, "CustomerID");
entity.HasIndex(e => e.CustomerId, "CustomersOrders");
entity.HasIndex(e => e.EmployeeId, "EmployeeID");
entity.HasIndex(e => e.EmployeeId, "EmployeesOrders");
entity.HasIndex(e => e.OrderDate, "OrderDate");
entity.HasIndex(e => e.ShipPostalCode, "ShipPostalCode");
entity.HasIndex(e => e.ShippedDate, "ShippedDate");
entity.HasIndex(e => e.ShipVia, "ShippersOrders");
entity.Property(e => e.OrderId).HasColumnName("OrderID");
entity.Property(e => e.CustomerId)
.HasMaxLength(5)
.HasColumnName("CustomerID")
.IsFixedLength(true);
entity.Property(e => e.EmployeeId).HasColumnName("EmployeeID");
entity.Property(e => e.Freight)
.HasColumnType("money")
.HasDefaultValueSql("((0))");
entity.Property(e => e.OrderDate).HasColumnType("datetime");
entity.Property(e => e.RequiredDate).HasColumnType("datetime");
entity.Property(e => e.ShipAddress).HasMaxLength(60);
entity.Property(e => e.ShipCity).HasMaxLength(15);
entity.Property(e => e.ShipCountry).HasMaxLength(15);
entity.Property(e => e.ShipName).HasMaxLength(40);
entity.Property(e => e.ShipPostalCode).HasMaxLength(10);
entity.Property(e => e.ShipRegion).HasMaxLength(15);
entity.Property(e => e.ShippedDate).HasColumnType("datetime");
entity.HasOne(d => d.Customer)
.WithMany(p => p.Orders)
.HasForeignKey(d => d.CustomerId)
.HasConstraintName("FK_Orders_Customers");
entity.HasOne(d => d.ShipViaNavigation)
.WithMany(p => p.Orders)
.HasForeignKey(d => d.ShipVia)
.HasConstraintName("FK_Orders_Shippers");
});
modelBuilder.Entity<OrderDetail>(entity => {
entity.HasKey(e => new { e.OrderId, e.ProductId })
.HasName("PK_Order_Details");
entity.ToTable("Order Details");
entity.HasIndex(e => e.OrderId, "OrderID");
entity.HasIndex(e => e.OrderId, "OrdersOrder_Details");
entity.HasIndex(e => e.ProductId, "ProductID");
entity.HasIndex(e => e.ProductId, "ProductsOrder_Details");
entity.Property(e => e.OrderId).HasColumnName("OrderID");
entity.Property(e => e.ProductId).HasColumnName("ProductID");
entity.Property(e => e.Quantity).HasDefaultValueSql("((1))");
entity.Property(e => e.UnitPrice).HasColumnType("money");
entity.HasOne(d => d.Order)
.WithMany(p => p.OrderDetails)
.HasForeignKey(d => d.OrderId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_Order_Details_Orders");
entity.HasOne(d => d.Product)
.WithMany(p => p.OrderDetails)
.HasForeignKey(d => d.ProductId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_Order_Details_Products");
});
modelBuilder.Entity<Product>(entity => {
entity.HasIndex(e => e.CategoryId, "CategoriesProducts");
entity.HasIndex(e => e.CategoryId, "CategoryID");
entity.HasIndex(e => e.ProductName, "ProductName");
entity.HasIndex(e => e.SupplierId, "SupplierID");
entity.HasIndex(e => e.SupplierId, "SuppliersProducts");
entity.Property(e => e.ProductId).HasColumnName("ProductID");
entity.Property(e => e.CategoryId).HasColumnName("CategoryID");
entity.Property(e => e.ProductName)
.IsRequired()
.HasMaxLength(40);
entity.Property(e => e.QuantityPerUnit).HasMaxLength(20);
entity.Property(e => e.ReorderLevel).HasDefaultValueSql("((0))");
entity.Property(e => e.SupplierId).HasColumnName("SupplierID");
entity.Property(e => e.UnitPrice)
.HasColumnType("money")
.HasDefaultValueSql("((0))");
entity.Property(e => e.UnitsInStock).HasDefaultValueSql("((0))");
entity.Property(e => e.UnitsOnOrder).HasDefaultValueSql("((0))");
entity.HasOne(d => d.Category)
.WithMany(p => p.Products)
.HasForeignKey(d => d.CategoryId)
.HasConstraintName("FK_Products_Categories");
entity.HasOne(d => d.Supplier)
.WithMany(p => p.Products)
.HasForeignKey(d => d.SupplierId)
.HasConstraintName("FK_Products_Suppliers");
});
modelBuilder.Entity<Shipper>(entity => {
entity.Property(e => e.ShipperId).HasColumnName("ShipperID");
entity.Property(e => e.CompanyName)
.IsRequired()
.HasMaxLength(40);
entity.Property(e => e.Phone).HasMaxLength(24);
});
modelBuilder.Entity<Supplier>(entity => {
entity.HasIndex(e => e.CompanyName, "CompanyName");
entity.HasIndex(e => e.PostalCode, "PostalCode");
entity.Property(e => e.SupplierId).HasColumnName("SupplierID");
entity.Property(e => e.Address).HasMaxLength(60);
entity.Property(e => e.City).HasMaxLength(15);
entity.Property(e => e.CompanyName)
.IsRequired()
.HasMaxLength(40);
entity.Property(e => e.ContactName).HasMaxLength(30);
entity.Property(e => e.ContactTitle).HasMaxLength(30);
entity.Property(e => e.Country).HasMaxLength(15);
entity.Property(e => e.Fax).HasMaxLength(24);
entity.Property(e => e.HomePage).HasColumnType("ntext");
entity.Property(e => e.Phone).HasMaxLength(24);
entity.Property(e => e.PostalCode).HasMaxLength(10);
entity.Property(e => e.Region).HasMaxLength(15);
});
modelBuilder.Entity<Employee>(entity => {
entity.HasIndex(e => e.EmployeeId, "EmployeeId");
entity.HasIndex(e => e.LastName, "LastName");
entity.HasIndex(e => e.FirstName, "FirstName");
entity.HasIndex(e => e.Title, "Title");
entity.HasIndex(e => e.BirthDate, "BirthDate");
entity.HasIndex(e => e.HireDate, "HireDate");
entity.HasIndex(e => e.Notes, "Notes");
});
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
}
using Microsoft.EntityFrameworkCore;
// ...
builder.Services.AddDbContextFactory<NorthwindContext>((sp, options) => {
var env = sp.GetRequiredService<IWebHostEnvironment>();
var dbPath = Path.Combine(env.ContentRootPath, "Northwind-5e44b51f.mdf");
options.UseSqlServer("Server=(localdb)\\MSSQLLocalDB;Integrated Security=true;AttachDbFileName=" + dbPath);
});
Run Demo: Grid - Interval Grouping
VIDEO
You can also implement custom logic to group grid data.
Note
The Grid does not support grouping by display text and custom grouping when you use a a Server Mode data source .
The Grid does not support interval grouping, custom grouping, or grouping by display text when you use a GridDevExtremeDataSource .
Custom Grouping
Follow the steps below to implement custom grouping logic:
Define a custom sorting algorithm (grouping relies on sort operations). To apply a custom algorithm, set the DxGridDataColumn.SortMode property to Custom
and handle the CustomSort event.
Set the DxGridDataColumn.GroupInterval
property to Custom
.
Handle the DxGrid.CustomGroup event and compare column values based on your custom logic. Use Value1 and Value2 event arguments to access compared values. To obtain other values from processed rows, call the GetRow1Value and GetRow2Value methods. To place compared values into the same group, set the SameGroup argument to true
.
In the event handler, set the Handled argument to true
to override the default grouping mechanism.
(Optional) Handle the CustomizeGroupValueDisplayText event to modify group row text.
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;
}
}
}
Run Demo: Grid - Custom Grouping
For more information about data grouping in the Grid component, refer to the following topic: Group Data in Blazor Grid .
See Also