Я пытаюсь создать библиотеку классов Razor (RCL), которую затем можно использовать в качестве многократно используемого набора элементов управления в моем приложении Blazor Server. Элемент управления RCL представляет собой таблицу, которая включает разбиение на страницы и сортировку столбцов. Поток данных для элемента управления заключается в том, что приложение Blazor обрабатывает все запросы данных, а затем передает данные в элемент управления RCL. Элемент управления RCL обрабатывает события пользовательского интерфейса (следующая/предыдущая разбивка на страницы) и отображение записей. У меня проблема в том, что текущее количество страниц (которое обновляется, когда пользователь щелкает следующую или предыдущую страницу) не сохраняется между событиями, поэтому количество никогда не меняется. Как я могу сохранять данные между событиями (я надеюсь отслеживать события пользовательского интерфейса в элементе управления RCL, а не в приложении Blazor с помощью элемента управления). Вот мой код (сокращенно):
Управление библиотекой классов Razor:
@if (employeeModels == null)
{
<p><em>Loading...</em></p>
}
else
{
//table with data ...
//controls to handle pagination
<div class = "pagination">
<button class = "btn btn-custom" @onclick=@(async ()=>await NavigateToPage("previous"))>Prev</button>
@for (int i = startPage; i <= endPage; i++)
{
var currentPage = i;
<button class = "btn btn-custom pagebutton @(currentPage==curPage?"btn-danger":"")" @onclick=@(async () =>await refreshRecords(currentPage))>
@currentPage
</button>
}
<button class = "btn btn-custom" @onclick=@(async ()=>await NavigateToPage("next"))>Next</button>
</div>
}
@code {
[Parameter]
public List<EmployeesModel> employeeModels { get; set; }
[Parameter]
public EventCallback<bool> RefreshDataEvent { get; set; }
int totalPages;
int totalRecords;
[Parameter]
public int TotalNumRecords { get; set; }
[Parameter]
public int curPage { get; set; }
[Parameter]
public int pagerSize{ get; set; }
[Parameter]
public int pageSize { get; set; }
int startPage;
int endPage;
[Parameter]
public string sortColumnName { get; set; } = "LastName";
[Parameter]
public string sortDir { get; set; } = "DESC";
protected override void OnParametersSet()
{
base.OnParametersSet();
totalRecords = TotalNumRecords;
totalPages = (int)Math.Ceiling(totalRecords / (decimal)pageSize);
SetPagerSize("forward");
}
public async Task refreshRecords(int currentPage)
{
curPage = currentPage;
await RefreshDataEvent.InvokeAsync(true);
this.StateHasChanged();
}
public void SetPagerSize(string direction)
{
if (direction == "forward" && endPage < totalPages)
{
startPage = endPage + 1;
if (endPage + pagerSize < totalPages)
{
endPage = startPage + pagerSize - 1;
}
else
{
endPage = totalPages;
}
this.StateHasChanged();
}
else if (direction == "back" && startPage > 1)
{
endPage = startPage - 1;
startPage = startPage - pagerSize;
}
}
public async Task NavigateToPage(string direction)
{
if (direction == "next")
{
if (curPage < totalPages)
{
if (curPage == endPage)
{
SetPagerSize("forward");
}
curPage += 1;
}
}
else if (direction == "previous")
{
if (curPage > 1)
{
if (curPage == startPage)
{
SetPagerSize("back");
}
curPage -= 1;
}
}
await refreshRecords(curPage);
}
}
Приложение Blazor с использованием элемента управления:
<SortablePaginatedEmployeeTable
employeeModels = "@employees"
curPage = "@paginationCurrentPage"
pageSize = "@paginationPageSize"
pagerSize = "@paginationPagerSize"
sortColumnName = "@paginationSortColumnName"
sortDir = "@paginationSortDirection"
RefreshDataEvent = "EmployeeListRefrshed"
@ref = "EmployeeTableControl"
TotalNumRecords = "@totalNumbEmployees"
GotToPageEven = "EmployeeNextClick" >
</SortablePaginatedEmployeeTable>
@code {
private SortablePaginatedEmployeeTable EmployeeTableControl;
int paginationCurrentPage = 1;
int paginationPageSize = 3;
int paginationPagerSize = 3;
string paginationSortColumnName = "LastName";
string paginationSortDirection = "Desc";
int totalNumbEmployees = 0;
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
await EmployeeListRefrshed();
}
private async Task EmployeeListRefrshed()
{
all_employees = await _db.ListAllEmployees((EmployeeTableControl.curPage - 1) * paginationPageSize, paginationPageSize, paginationSortColumnName, paginationSortDirection);
totalNumbEmployees = _db.CountNumberEmployees();
foreach(var e in all_employees)
{
employees.Add(new EmployeesModel { Email = e.Email, FirstName = e.FirstName, LastName = e.LastName, Id = e.Id, PhoneNumber = e.PhoneNumber });
}
}
}
С этим кодом, когда пользователь нажимает «Далее», вызывается функция NavigateToPage, но она всегда возвращает 2. Я полагаю, это потому, что данные не сохраняются между нажатиями кнопок? Как я могу решить эту проблему?
@jason Ваш элемент управления — это компонент Blazor, написанный на разметке Razor. На самом деле он просто компилируется в стандартный класс DotNetCore, наследуемый от ComponentBase
.
@ Роберто. Спасибо. Да, первоначальная загрузка целевой страницы мучительна, но я не сторонник использования OnAfterRender
. Я бы хотел, чтобы у нас была опция загрузки статической страницы для предварительного рендеринга сервера! Я склонен выступать за облегченную целевую страницу, если это возможно.
Ваша проблема заключается в обновлении Parameter
в компоненте. Это в основном NONO. Читайте их, используйте, но никогда не изменяйте.
Когда вы запускаете RefreshDataEvent
, он вызывает EmployeeListRefrshed, который получает данные. Это обновление employees
. Когда EmployeeListRefrshed
завершит рендеринг компонента. Это включает в себя запуск повторного рендеринга SortablePaginatedEmployeeTable
. paginationCurrentPage
по-прежнему имеет значение 1, поэтому компонент повторно отображается на странице 1.
Вам нужно сделать что-то вроде:
Составная часть
[Parameter]
public EventCallback<int> RefreshDataEvent { get; set; }
public async Task refreshRecords(int currentPage)
{
await RefreshDataEvent.InvokeAsync(currentPage);
// probably not needed
this.StateHasChanged();
}
Страница
private async Task EmployeeListRefrshed(int pageNo)
{
all_employees = await _db.ListAllEmployees((pageNo - 1) * paginationPageSize, paginationPageSize, paginationSortColumnName, paginationSortDirection);
totalNumbEmployees = _db.CountNumberEmployees();
foreach(var e in all_employees)
{
employees.Add(new EmployeesModel { Email = e.Email, FirstName = e.FirstName, LastName = e.LastName, Id = e.Id, PhoneNumber = e.PhoneNumber });
}
this.pagingationcurrentpage = pageNo
}
Хорошее решение +1. В .NET 6 есть что-то новое, называемое постоянное состояние компонента. Я еще мало что знаю об этом, но мне интересно, может ли это быть полезно для таких проблем, как эта.
@ Роберто. Не видел этого в списке новых функций. Ты узнаешь что-то новое каждый день. Я посмотрю.
Спасибо! Да, я в итоге сделал что-то подобное. Вместо передачи PageNo в EmployeeListRefrshed я использовал директиву @bind для привязки переменной. Таким образом, не нужно беспокоиться о передаче переменных. Тем не менее, это тоже работает. Спасибо!
@Roberto, но мой элемент управления написан на Razor, а не на Blazor. Я пытаюсь создать повторно используемую библиотеку классов Razor, которую я могу использовать в приложениях Blazor. Я хочу сохранить все управление состоянием контроля внутри контроля. Я не уверен, какой ответ вы имели в виду в предложенном посте, но они, похоже, относятся к Blazor.