A server-side paginated grid. Pages are fetched on demand via
IBnPagedDataService<TItem>, keeping memory usage flat regardless of
total data set size. Sorting, filtering, and search are forwarded to the data service.
Implement IBnPagedDataService<TItem> to connect the grid to any data
source — an API, database, or in-memory list. The method receives a
BnPageRequest containing page range, sort descriptors, search text, and
filters, and must return a StandardResponse<BnPagedResults<TItem>>.
public class EmployeeService : IBnPagedDataService<Employee>
{
public async Task<StandardResponse<BnPagedResults<Employee>>> GetPagesAsync(
BnPageRequest request, CancellationToken ct = default)
{
var query = _db.Employees.AsQueryable();
// Apply search
if (!string.IsNullOrWhiteSpace(request.SearchText))
query = query.Where(x => x.Name.Contains(request.SearchText));
// Apply sort
if (request.Sorters?.Any() == true)
{
var s = request.Sorters.First();
query = s.Direction == SortDirection.Ascending
? query.OrderBy(x => EF.Property<object>(x, s.Field))
: query.OrderByDescending(x => EF.Property<object>(x, s.Field));
}
var total = await query.CountAsync(ct);
var results = new BnPagedResults<Employee>
{
PageSize = request.PageSize,
TotalItems = total
};
for (var p = request.StartPage; p <= request.EndPage; p++)
{
var items = await query
.Skip(p * request.PageSize).Take(request.PageSize)
.ToListAsync(ct);
results.Add(new BnPageResult<Employee>
{
Page = p,
Items = items,
ReturnedUTC = DateTime.UtcNow
});
}
return StandardResponse.Succeeded(results);
}
}
Pass your service to PagedDataService. Column definitions are identical to
BnGrid. The built-in search icon and pagination controls are included
automatically.
PageSize controls how many rows appear per page.
CachedPages specifies how many adjacent pages are pre-fetched in a single
request — reducing round trips when the user pages forward or backward.
<!-- Show 25 rows per page, pre-fetch 3 pages per request -->
<BnPagedGrid TItem="Employee"
PagedDataService="_service"
PageSize="25"
CachedPages="3">
<Columns>...</Columns>
</BnPagedGrid>
Set VirtualScroll="true" to replace the pagination footer with infinite
virtual scrolling. The grid fetches PageSize rows at a time from the data
service as the user scrolls — in the example below, 500 employees are served 20 at a time.
Sorting, filtering, and search continue to work; the grid automatically re-fetches data
when these change.
You can also set Virtualize="true" (without VirtualScroll) to
virtualize rows within the current page while keeping the pagination controls.
<!-- Virtualize rows within each page, keep pagination -->
<BnPagedGrid TItem="Employee" PagedDataService="_service"
Virtualize="true" Height="400" PageSize="100"
DefaultSortBy="x => x.Name">
<Columns>...</Columns>
</BnPagedGrid>
Set SelectionMode to enable row-click selection. Works with all rendering modes
including pagination and virtual scroll. Selection is cleared when navigating to a new page
or reloading data.
<BnPagedGrid TItem="Employee" PagedDataService="_service"
SelectionMode="GridSelectionMode.Single"
OnSelectionChanged="items => _selected = items">
<Columns>
<BnGridColumn TItem="Employee" Header="Name" Property="x => x.Name" />
</Columns>
</BnPagedGrid>
Add, Edit, and Delete buttons appear automatically when their EventCallback is
set. Use ToolbarContent for custom buttons. Set ShowToolbar="false"
to hide the header bar entirely.
Use ToolbarContent to add custom buttons on the left and
RightToolbarContent for the right side. Set ShowSearch="false"
to hide the search box.
The paged grid also supports adaptive mode. By default
(AdaptiveMode="GridAdaptiveMode.Responsive"), the grid switches to a stacked card
layout when the container width drops below the breakpoint. Pagination continues to work normally
in adaptive mode.