Сохранение данных между событиями в элементе управления Razor Class Library

Я пытаюсь создать библиотеку классов 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. Я полагаю, это потому, что данные не сохраняются между нажатиями кнопок? Как я могу решить эту проблему?

@Roberto, но мой элемент управления написан на Razor, а не на Blazor. Я пытаюсь создать повторно используемую библиотеку классов Razor, которую я могу использовать в приложениях Blazor. Я хочу сохранить все управление состоянием контроля внутри контроля. Я не уверен, какой ответ вы имели в виду в предложенном посте, но они, похоже, относятся к Blazor.

jason 02.04.2022 15:06

@jason Ваш элемент управления — это компонент Blazor, написанный на разметке Razor. На самом деле он просто компилируется в стандартный класс DotNetCore, наследуемый от ComponentBase.

MrC aka Shaun Curtis 02.04.2022 19:00

@ Роберто. Спасибо. Да, первоначальная загрузка целевой страницы мучительна, но я не сторонник использования OnAfterRender. Я бы хотел, чтобы у нас была опция загрузки статической страницы для предварительного рендеринга сервера! Я склонен выступать за облегченную целевую страницу, если это возможно.

MrC aka Shaun Curtis 02.04.2022 21:50
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
70
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваша проблема заключается в обновлении 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 есть что-то новое, называемое постоянное состояние компонента. Я еще мало что знаю об этом, но мне интересно, может ли это быть полезно для таких проблем, как эта.

Yogi 02.04.2022 22:04

@ Роберто. Не видел этого в списке новых функций. Ты узнаешь что-то новое каждый день. Я посмотрю.

MrC aka Shaun Curtis 02.04.2022 22:16

Спасибо! Да, я в итоге сделал что-то подобное. Вместо передачи PageNo в EmployeeListRefrshed я использовал директиву @bind для привязки переменной. Таким образом, не нужно беспокоиться о передаче переменных. Тем не менее, это тоже работает. Спасибо!

jason 03.04.2022 01:19

Другие вопросы по теме