Adam O'Neil aosoftware.net 1/12/21

Unfortunately I don't have a fully open-source example, but I will show all my steps that I'm using to achieve server-side paging in queries used with Radzen Grid.

In a nutshell I have

https://adamosoftware.blob.core.windows.net:443/images/pager-action.gif

In more detail

  1. Start with a Pager component. This renders as a pair of buttons pointing left and right (using the Open Iconic icons in the default Blazor project template.) The point of this is to have something user can click on to cycle pages backward and forward. Currently, I do not display the total number of pages in a query, just the current page. My page numbers are 0-based, but displayed as 1-based.
<div class="d-flex align-items-center ml-2">
    @if (Page > 0)
    {
        <button class="btn btn-outline-secondary" type="button" @onclick="@((args) => Navigate(-1))">
            <span class="oi oi-caret-left"></span>
        </button>
    }
    
    <span class="mx-3">@(Page + 1)</span>

    <button class="btn btn-outline-secondary" type="button" @onclick="@((args) => Navigate(1))">
        <span class="oi oi-caret-right"></span>
    </button>
</div>

@code {
    [Parameter]
    public int Page { get; set; }

    [Parameter]
    public EventCallback<int> PageChanged { get; set; }

    public void SetPage(int page)
    {
        Page = page;
        StateHasChanged();
    }

    async Task Navigate(int direction)
    {
        Page += direction;
        await PageChanged.InvokeAsync(Page);
    }
}
  1. Create a Query<T> class that encapsulates your query. Here's some info about how I do this from the Dapper.QX wiki. Your query class should have a Page property with an [Offset] attribute. On the page where you'll implement a pageable grid, have an instance of your query. My example is called ProjectsQuery, and it has some criteria including an "active" filter and a start page of 0. I have a couple other necessary variables, one of the main grid, and one representing the query result data.
RadzenGrid<ProjectsQueryResult> grid;
IEnumerable<ProjectsQueryResult> data;
ProjectsQuery query = new ProjectsQuery() { IsActive = true, Page = 0 };
  1. On your page with the Radzen grid, have an EditForm that binds to your query object. This will contain your Pager component. Note that my example has a couple other things — a Radzen dropdown and text box, along with my ActiveFilter component (a separate topic), my standard way of filtering for "active" or "inactive" items in a list.

Note that the button element has an @onclick event that sets the query page to 0. This is so every time the user clicks Search, the results always start on the first page. Note also how the Pager component handles the PageChanged event by setting the query.Page property to the Pager's currently selected page, and it calls the main page's RefreshList method.

<EditForm Model="query" OnSubmit="RefreshList" class="form-inline">
    <label class="mr-2">Manager:</label>
    <RadzenDropDown Data="employees" ValueProperty="Id" TextProperty="DisplayName" @bind-Value="query.ManagerId" AllowClear="true" class="mr-2"/>

    <label class="mr-2">Search:</label>
    <RadzenTextBox @bind-Value="query.Search" class="mr-2"/>            

    <ActiveFilter @bind-Value="query.IsActive" Style="width:120px"/>

    <button class="btn btn-secondary ml-2" @onclick="@((args) => query.Page = 0)">Search</button>

    <Pager PageChanged="@(async (page) => { query.Page = page; await RefreshList(); })" @ref="pager" Page="@(query.Page ?? 0)"/>
</EditForm>
  1. RefreshList is a method in my main page. The important part of it looks like this. This is using my Dapper AspNetCore package to inject data access capabilities to components. This is a separate topic I can go into if you like. The important part of it here is to be able to execute my query and fill the Radzen grid with data.
@inject DapperCX<int, User> Data

async Task RefreshList()
{
    // main grid
    data = await Data.QueryAsync(query);
}