mirror of
https://github.com/radzenhq/radzen-blazor.git
synced 2026-07-08 18:16:08 +00:00
682 lines
23 KiB
C#
682 lines
23 KiB
C#
using Microsoft.AspNetCore.Components;
|
|
using Microsoft.AspNetCore.Components.Web;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.JSInterop;
|
|
using Radzen.Blazor.Rendering;
|
|
|
|
namespace Radzen.Blazor
|
|
{
|
|
/// <summary>
|
|
/// A pagination component that provides navigation controls for paged data display.
|
|
/// RadzenPager displays page numbers, navigation buttons, and optional page size selector for navigating through large datasets.
|
|
/// Works standalone or integrated with data components like RadzenDataGrid and RadzenDataList.
|
|
/// Provides navigation buttons (First/Previous/Next/Last page with customizable labels and icons), clickable page number buttons with configurable count,
|
|
/// optional dropdown to change items per page, summary display ("Page X of Y" or custom summary text), alignment controls (left/center/right) via HorizontalAlign,
|
|
/// compact or default spacing density, and ARIA labels for all buttons for accessibility.
|
|
/// The PageChanged event provides Skip and Top values for loading the correct page of data.
|
|
/// Use Count to specify total items, PageSize for items per page, and PageNumbersCount for visible page buttons.
|
|
/// </summary>
|
|
/// <example>
|
|
/// Basic pager:
|
|
/// <code>
|
|
/// <RadzenPager Count=@totalCount PageSize="20" PageNumbersCount="5" PageChanged=@LoadPage />
|
|
/// @code {
|
|
/// int totalCount = 250;
|
|
/// async Task LoadPage(PagerEventArgs args)
|
|
/// {
|
|
/// // Load items from args.Skip, take args.Top
|
|
/// }
|
|
/// }
|
|
/// </code>
|
|
/// Pager with page size selector:
|
|
/// <code>
|
|
/// <RadzenPager Count=@totalCount PageSize=@pageSize PageSizeChanged=@OnPageSizeChanged
|
|
/// PageSizeOptions=@(new int[] { 10, 20, 50, 100 }) ShowPagingSummary="true" />
|
|
/// </code>
|
|
/// </example>
|
|
public partial class RadzenPager : RadzenComponent
|
|
{
|
|
/// <inheritdoc />
|
|
protected override string GetComponentCssClass() => ClassList.Create("rz-pager rz-unselectable-text rz-helper-clearfix")
|
|
.Add("rz-density-compact", Density == Density.Compact)
|
|
.AddHorizontalAlign(HorizontalAlign)
|
|
.ToString();
|
|
|
|
private string? firstPageTitle;
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether the reload button is shown.
|
|
/// </summary>
|
|
/// <value><c>true</c> if the reload button is visible; otherwise, <c>false</c>. Default is <c>false</c>.</value>
|
|
[Parameter]
|
|
public bool AllowReload { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the pager's reload button's title attribute.
|
|
/// </summary>
|
|
[Parameter]
|
|
public string ReloadTitle { get; set; } = "Reload";
|
|
|
|
/// <summary>
|
|
/// Gets or sets the pager's reload button's aria-label attribute.
|
|
/// </summary>
|
|
[Parameter]
|
|
public string ReloadAriaLabel { get; set; } = "Reload current page.";
|
|
|
|
/// <summary>
|
|
/// Gets or sets the reload callback.
|
|
/// </summary>
|
|
/// <value>The reload callback.</value>
|
|
[Parameter]
|
|
public EventCallback PageReload { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the pager's first page button's title attribute.
|
|
/// </summary>
|
|
[Parameter]
|
|
public string FirstPageTitle { get => firstPageTitle ?? Localize(nameof(RadzenStrings.Pager_FirstPageTitle)); set => firstPageTitle = value; }
|
|
|
|
private string? firstPageAriaLabel;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the pager's first page button's aria-label attribute.
|
|
/// </summary>
|
|
[Parameter]
|
|
public string FirstPageAriaLabel { get => firstPageAriaLabel ?? Localize(nameof(RadzenStrings.Pager_FirstPageAriaLabel)); set => firstPageAriaLabel = value; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the pager's optional previous page button's label text.
|
|
/// </summary>
|
|
[Parameter]
|
|
public string? PrevPageLabel { get; set; }
|
|
|
|
private string? prevPageTitle;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the pager's previous page button's title attribute.
|
|
/// </summary>
|
|
[Parameter]
|
|
public string PrevPageTitle { get => prevPageTitle ?? Localize(nameof(RadzenStrings.Pager_PrevPageTitle)); set => prevPageTitle = value; }
|
|
|
|
private string? prevPageAriaLabel;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the pager's previous page button's aria-label attribute.
|
|
/// </summary>
|
|
[Parameter]
|
|
public string PrevPageAriaLabel { get => prevPageAriaLabel ?? Localize(nameof(RadzenStrings.Pager_PrevPageAriaLabel)); set => prevPageAriaLabel = value; }
|
|
|
|
private string? lastPageTitle;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the pager's last page button's title attribute.
|
|
/// </summary>
|
|
[Parameter]
|
|
public string LastPageTitle { get => lastPageTitle ?? Localize(nameof(RadzenStrings.Pager_LastPageTitle)); set => lastPageTitle = value; }
|
|
|
|
private string? lastPageAriaLabel;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the pager's last page button's aria-label attribute.
|
|
/// </summary>
|
|
[Parameter]
|
|
public string LastPageAriaLabel { get => lastPageAriaLabel ?? Localize(nameof(RadzenStrings.Pager_LastPageAriaLabel)); set => lastPageAriaLabel = value; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the pager's optional next page button's label text.
|
|
/// </summary>
|
|
[Parameter]
|
|
public string? NextPageLabel { get; set; }
|
|
|
|
private string? nextPageTitle;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the pager's next page button's title attribute.
|
|
/// </summary>
|
|
[Parameter]
|
|
public string NextPageTitle { get => nextPageTitle ?? Localize(nameof(RadzenStrings.Pager_NextPageTitle)); set => nextPageTitle = value; }
|
|
|
|
private string? nextPageAriaLabel;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the pager's next page button's aria-label attribute.
|
|
/// </summary>
|
|
[Parameter]
|
|
public string NextPageAriaLabel { get => nextPageAriaLabel ?? Localize(nameof(RadzenStrings.Pager_NextPageAriaLabel)); set => nextPageAriaLabel = value; }
|
|
|
|
private string? pageTitleFormat;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the pager's numeric page number buttons' title attributes.
|
|
/// </summary>
|
|
[Parameter]
|
|
public string PageTitleFormat { get => pageTitleFormat ?? Localize(nameof(RadzenStrings.Pager_PageTitleFormat)); set => pageTitleFormat = value; }
|
|
|
|
private string? pageAriaLabelFormat;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the pager's numeric page number buttons' aria-label attributes.
|
|
/// </summary>
|
|
[Parameter]
|
|
public string PageAriaLabelFormat { get => pageAriaLabelFormat ?? Localize(nameof(RadzenStrings.Pager_PageAriaLabelFormat)); set => pageAriaLabelFormat = value; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the horizontal align.
|
|
/// </summary>
|
|
/// <value>The horizontal align.</value>
|
|
[Parameter]
|
|
public HorizontalAlign HorizontalAlign { get; set; } = HorizontalAlign.Justify;
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating Pager density.
|
|
/// </summary>
|
|
[Parameter]
|
|
public Density Density { get; set; } = Density.Default;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the page size.
|
|
/// </summary>
|
|
/// <value>The page size.</value>
|
|
[Parameter]
|
|
public int PageSize { get; set; } = 10;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the page size changed callback.
|
|
/// </summary>
|
|
/// <value>The page size changed callback.</value>
|
|
[Parameter]
|
|
public EventCallback<int> PageSizeChanged { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the page size options.
|
|
/// </summary>
|
|
/// <value>The page size options.</value>
|
|
[Parameter]
|
|
public IEnumerable<int>? PageSizeOptions { get; set; }
|
|
|
|
private string? pageSizeText;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the page size description text.
|
|
/// </summary>
|
|
/// <value>The page size description text.</value>
|
|
[Parameter]
|
|
public string PageSizeText { get => pageSizeText ?? Localize(nameof(RadzenStrings.Pager_PageSizeText)); set => pageSizeText = value; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the pager summary visibility.
|
|
/// </summary>
|
|
/// <value>The pager summary visibility.</value>
|
|
[Parameter]
|
|
public bool ShowPagingSummary { get; set; }
|
|
|
|
private string? navigationAriaLabel;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the navigation aria-label.
|
|
/// </summary>
|
|
[Parameter]
|
|
public string NavigationAriaLabel { get => navigationAriaLabel ?? Localize(nameof(RadzenStrings.Pager_NavigationAriaLabel)); set => navigationAriaLabel = value; }
|
|
|
|
private string? pagingSummaryFormat;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the pager summary format. <see cref="PagingSummaryTemplate" /> has preference over this property.
|
|
/// </summary>
|
|
/// <value>The pager summary format.</value>
|
|
[Parameter]
|
|
public string PagingSummaryFormat { get => pagingSummaryFormat ?? Localize(nameof(RadzenStrings.Pager_PagingSummaryFormat)); set => pagingSummaryFormat = value; }
|
|
|
|
#nullable enable
|
|
/// <summary>
|
|
/// Gets or sets the pager summary template. Has preference over <see cref="PagingSummaryFormat" />.
|
|
/// </summary>
|
|
[Parameter]
|
|
public RenderFragment<PagingInformation>? PagingSummaryTemplate { get; set; }
|
|
#nullable restore
|
|
|
|
/// <summary>
|
|
/// Gets or sets the page numbers count.
|
|
/// </summary>
|
|
/// <value>The page numbers count.</value>
|
|
[Parameter]
|
|
public int PageNumbersCount { get; set; } = 5;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the total items count.
|
|
/// </summary>
|
|
/// <value>The total items count.</value>
|
|
[Parameter]
|
|
public int Count { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets the current page.
|
|
/// </summary>
|
|
/// <value>The current page.</value>
|
|
public int CurrentPage
|
|
{
|
|
get
|
|
{
|
|
return GetPage();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the visible.
|
|
/// </summary>
|
|
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
|
|
protected bool GetVisible()
|
|
{
|
|
return Visible && (AlwaysVisible || Count > PageSize || (PageSizeOptions != null && PageSizeOptions.Any()));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether pager is visible even when not enough data for paging.
|
|
/// </summary>
|
|
/// <value><c>true</c> if pager is visible even when not enough data for paging otherwise, <c>false</c>.</value>
|
|
[Parameter]
|
|
public bool AlwaysVisible { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the page changed callback.
|
|
/// </summary>
|
|
/// <value>The page changed callback.</value>
|
|
[Parameter]
|
|
public EventCallback<PagerEventArgs> PageChanged { get; set; }
|
|
|
|
/// <summary>
|
|
/// Reloads this instance.
|
|
/// </summary>
|
|
public async virtual Task Reload()
|
|
{
|
|
await InvokeAsync(CalculatePager);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when parameters set asynchronous.
|
|
/// </summary>
|
|
/// <returns>Task.</returns>
|
|
protected override Task OnParametersSetAsync()
|
|
{
|
|
if (GetVisible())
|
|
{
|
|
InvokeAsync(Reload);
|
|
}
|
|
|
|
return base.OnParametersSetAsync();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when page size changed.
|
|
/// </summary>
|
|
/// <param name="value">The value.</param>
|
|
protected async Task OnPageSizeChanged(object value)
|
|
{
|
|
bool isFirstPage = CurrentPage == 0;
|
|
bool isLastPage = CurrentPage == numberOfPages - 1 && numberOfPages > 1;
|
|
int prevSkip = skip;
|
|
PageSize = (int)value;
|
|
await InvokeAsync(Reload);
|
|
await PageSizeChanged.InvokeAsync((int)value);
|
|
if (isLastPage)
|
|
{
|
|
await LastPage();
|
|
}
|
|
else if (!isFirstPage)
|
|
{
|
|
int newPage = (int)Math.Floor((decimal)(prevSkip / (PageSize > 0 ? PageSize : 10)));
|
|
await GoToPage(newPage, true);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets number of recrods to skip.
|
|
/// </summary>
|
|
protected int skip;
|
|
|
|
/// <summary>
|
|
/// Gets or sets number of page links.
|
|
/// </summary>
|
|
protected int numberOfPageLinks = 5;
|
|
|
|
/// <summary>
|
|
/// Gets or sets start page.
|
|
/// </summary>
|
|
protected int startPage;
|
|
|
|
/// <summary>
|
|
/// Gets or sets end page.
|
|
/// </summary>
|
|
protected int endPage;
|
|
|
|
/// <summary>
|
|
/// Gets or sets number of pages.
|
|
/// </summary>
|
|
protected int numberOfPages;
|
|
|
|
/// <summary>
|
|
/// Calculates the pager.
|
|
/// </summary>
|
|
protected void CalculatePager()
|
|
{
|
|
var pageSize = PageSize > 0 ? PageSize : 10;
|
|
numberOfPages = (int)Math.Ceiling((decimal)Count / pageSize);
|
|
|
|
if (numberOfPages < 1)
|
|
{
|
|
numberOfPages = 1;
|
|
}
|
|
|
|
int visiblePages = Math.Min(PageNumbersCount, numberOfPages);
|
|
|
|
startPage = (int)Math.Max(0, Math.Ceiling((decimal)(CurrentPage - (visiblePages / 2))));
|
|
endPage = Math.Min(numberOfPages - 1, startPage + visiblePages - 1);
|
|
|
|
var delta = PageNumbersCount - (endPage - startPage + 1);
|
|
startPage = Math.Max(0, startPage - delta);
|
|
|
|
if (skip == Count)
|
|
{
|
|
skip = pageSize * (numberOfPages - 1);
|
|
//InvokeAsync(Reload);
|
|
//PageChanged.InvokeAsync(new PagerEventArgs() { Skip = skip, Top = PageSize, PageIndex = CurrentPage });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the page.
|
|
/// </summary>
|
|
/// <returns>System.Int32.</returns>
|
|
protected int GetPage()
|
|
{
|
|
return skip / (PageSize > 0 ? PageSize : 10);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Goes to specified page.
|
|
/// </summary>
|
|
/// <param name="page">The page.</param>
|
|
/// <param name="forceReload">if set to <c>true</c> [force reload].</param>
|
|
public async Task GoToPage(int page, bool forceReload = false)
|
|
{
|
|
if (CurrentPage != page || forceReload)
|
|
{
|
|
skip = page * PageSize;
|
|
await InvokeAsync(Reload);
|
|
await PageChanged.InvokeAsync(new PagerEventArgs() { Skip = skip, Top = PageSize, PageIndex = CurrentPage });
|
|
StateHasChanged();
|
|
}
|
|
}
|
|
|
|
async Task OnFirstPageClick()
|
|
{
|
|
focusedIndex = -2;
|
|
|
|
await FirstPage();
|
|
|
|
if (skip == 0)
|
|
{
|
|
focusedIndex = focusedIndex + 2;
|
|
shouldFocus = true;
|
|
}
|
|
}
|
|
|
|
async Task OnPrevPageClick()
|
|
{
|
|
focusedIndex = -1;
|
|
|
|
await PrevPage();
|
|
|
|
if (skip == 0)
|
|
{
|
|
focusedIndex++;
|
|
shouldFocus = true;
|
|
}
|
|
}
|
|
|
|
async Task OnPageClick(int i, int startPage)
|
|
{
|
|
focusedIndex = i - startPage;
|
|
await GoToPage(i);
|
|
}
|
|
|
|
async Task OnNextPageClick(int endPage)
|
|
{
|
|
focusedIndex = Math.Min(endPage + 1, PageNumbersCount);
|
|
|
|
await NextPage();
|
|
|
|
if (CurrentPage == numberOfPages - 1)
|
|
{
|
|
focusedIndex--;
|
|
shouldFocus = true;
|
|
}
|
|
}
|
|
|
|
async Task OnLastPageClick(int endPage)
|
|
{
|
|
focusedIndex = Math.Min(endPage + 1, PageNumbersCount) + 1;
|
|
|
|
await LastPage();
|
|
|
|
if (CurrentPage == numberOfPages - 1)
|
|
{
|
|
focusedIndex = focusedIndex - 2;
|
|
shouldFocus = true;
|
|
}
|
|
}
|
|
|
|
async Task OnReloadClick()
|
|
{
|
|
await PageReload.InvokeAsync();
|
|
await PageChanged.InvokeAsync(new PagerEventArgs() { Skip = skip, Top = PageSize, PageIndex = CurrentPage });
|
|
}
|
|
|
|
internal void ChangeState()
|
|
{
|
|
StateHasChanged();
|
|
}
|
|
|
|
internal void SetCurrentPage(int page)
|
|
{
|
|
if (CurrentPage != page)
|
|
{
|
|
skip = page * PageSize;
|
|
}
|
|
}
|
|
|
|
internal void SetCount(int count)
|
|
{
|
|
Count = count;
|
|
CalculatePager();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Goes to first page.
|
|
/// </summary>
|
|
/// <param name="forceReload">if set to <c>true</c> [force reload].</param>
|
|
public async Task FirstPage(bool forceReload = false)
|
|
{
|
|
if (CurrentPage != 0 || forceReload)
|
|
{
|
|
skip = 0;
|
|
await InvokeAsync(Reload);
|
|
await PageChanged.InvokeAsync(new PagerEventArgs() { Skip = skip, Top = PageSize, PageIndex = CurrentPage });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Goes to previous page.
|
|
/// </summary>
|
|
public async Task PrevPage()
|
|
{
|
|
var newskip = skip - PageSize < 0 ? 0 : skip - PageSize;
|
|
if (newskip != skip)
|
|
{
|
|
skip = newskip;
|
|
await InvokeAsync(Reload);
|
|
await PageChanged.InvokeAsync(new PagerEventArgs() { Skip = skip, Top = PageSize, PageIndex = CurrentPage });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Goes to next page.
|
|
/// </summary>
|
|
public async Task NextPage()
|
|
{
|
|
var newskip = PageSize * (CurrentPage < (numberOfPages - 1) ? CurrentPage + 1 : numberOfPages - 1);
|
|
if (newskip != skip)
|
|
{
|
|
skip = newskip;
|
|
await InvokeAsync(Reload);
|
|
await PageChanged.InvokeAsync(new PagerEventArgs() { Skip = skip, Top = PageSize, PageIndex = CurrentPage });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Goes to last page.
|
|
/// </summary>
|
|
public async Task LastPage()
|
|
{
|
|
var newskip = PageSize * (numberOfPages - 1);
|
|
if (newskip != skip)
|
|
{
|
|
skip = newskip;
|
|
await InvokeAsync(Reload);
|
|
await PageChanged.InvokeAsync(new PagerEventArgs() { Skip = skip, Top = PageSize, PageIndex = CurrentPage });
|
|
}
|
|
}
|
|
|
|
bool preventKeyDown;
|
|
bool stopKeydownPropagation;
|
|
int focusedIndex = -3;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the tabindex applied to the currently active pager button. All other pager buttons get tabindex <c>-1</c> following the roving tabindex pattern.
|
|
/// </summary>
|
|
/// <value>The tabindex of the active pager button. Default is <c>0</c>.</value>
|
|
[Parameter]
|
|
public int TabIndex { get; set; }
|
|
|
|
int RovingIndex
|
|
{
|
|
get
|
|
{
|
|
if (focusedIndex == -3)
|
|
{
|
|
var numberOfDisplayedPages = Math.Min(endPage + 1, PageNumbersCount);
|
|
|
|
return Math.Clamp(CurrentPage - startPage, 0, Math.Max(numberOfDisplayedPages - 1, 0));
|
|
}
|
|
|
|
return focusedIndex;
|
|
}
|
|
}
|
|
|
|
string GetButtonTabIndex(int index)
|
|
{
|
|
return index == RovingIndex ? TabIndex.ToString(System.Globalization.CultureInfo.InvariantCulture) : "-1";
|
|
}
|
|
|
|
string ActiveButtonId
|
|
{
|
|
get
|
|
{
|
|
var numberOfDisplayedPages = Math.Min(endPage + 1, PageNumbersCount);
|
|
var index = RovingIndex;
|
|
|
|
if (index == -2)
|
|
{
|
|
return $"{GetId()}fp";
|
|
}
|
|
if (index == -1)
|
|
{
|
|
return $"{GetId()}pp";
|
|
}
|
|
if (index == numberOfDisplayedPages)
|
|
{
|
|
return $"{GetId()}np";
|
|
}
|
|
if (index == numberOfDisplayedPages + 1)
|
|
{
|
|
return $"{GetId()}lp";
|
|
}
|
|
|
|
return $"{GetId()}{startPage + index}p";
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handles the key down event.
|
|
/// </summary>
|
|
/// <param name="args">The <see cref="KeyboardEventArgs"/> instance containing the event data.</param>
|
|
protected virtual Task OnKeyDown(KeyboardEventArgs args)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(args);
|
|
var key = args.Code != null ? args.Code : args.Key;
|
|
|
|
var numberOfDisplayedPages = Math.Min(endPage + 1, PageNumbersCount);
|
|
|
|
if (key == "ArrowLeft" || key == "ArrowRight" || key == "Home" || key == "End")
|
|
{
|
|
preventKeyDown = true;
|
|
stopKeydownPropagation = true;
|
|
|
|
if (key == "Home")
|
|
{
|
|
focusedIndex = -2;
|
|
}
|
|
else if (key == "End")
|
|
{
|
|
focusedIndex = numberOfDisplayedPages + 1;
|
|
}
|
|
else
|
|
{
|
|
focusedIndex = Math.Clamp(RovingIndex + (key == "ArrowLeft" ? -1 : 1), -2, numberOfDisplayedPages + 1);
|
|
}
|
|
|
|
if (CurrentPage == 0 && focusedIndex < 0)
|
|
{
|
|
focusedIndex = 0;
|
|
}
|
|
else if (CurrentPage == numberOfPages - 1 && focusedIndex > numberOfDisplayedPages - 1)
|
|
{
|
|
focusedIndex = numberOfDisplayedPages - 1;
|
|
}
|
|
|
|
shouldFocus = true;
|
|
}
|
|
else
|
|
{
|
|
preventKeyDown = false;
|
|
stopKeydownPropagation = false;
|
|
}
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
bool shouldFocus;
|
|
|
|
/// <inheritdoc />
|
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
{
|
|
await base.OnAfterRenderAsync(firstRender);
|
|
|
|
if (shouldFocus && JSRuntime != null)
|
|
{
|
|
shouldFocus = false;
|
|
try
|
|
{
|
|
await JSRuntime.InvokeVoidAsync("Radzen.focusElement", ActiveButtonId);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|