@inject IJSRuntime JS @inject State State @implements IDisposable @if (Editable) { } @if(statuses != null) foreach(Status status in statuses) { } @code { [Parameter] public Func?>> StatusFunc { get; set; } [Parameter] public bool Editable { get; set; } = false; public EditStatusDialog? Dialog { get; set; } private List? statuses; private int count { get; set; } = 0; private int pageSize { get; } = 50; protected override async Task OnInitializedAsync() { await base.OnInitializedAsync(); State.PropertyChanged += StateChanged; State.CanRefresh = true; if (statuses == null || statuses.Count == 0) await LoadNext(); await InvokeAsync(StateHasChanged); await JS.InvokeVoidAsync("removeElementById", "statusLoading"); } public async Task PullUp() { int countBefore = count; await LoadNext(); return (count != countBefore); } public async Task LoadNext(bool forceRefresh = false) { if (statuses == null) statuses = new List(); if (forceRefresh) { count = 0; statuses.Clear(); } var allStatuses = await StatusFunc(forceRefresh); if (allStatuses != null && count < allStatuses.Count) { statuses.AddRange(allStatuses.Skip(count).Take(pageSize)); count = statuses.Count; } await InvokeAsync(StateHasChanged); } private async void StateChanged(object? sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(State.IsRefreshing) && State.IsRefreshing) { await LoadNext(true); State.IsRefreshing = false; } if(e.PropertyName == nameof(State.AtBottom) && State.AtBottom) { await LoadNext(); } } public void Dispose() { State.PropertyChanged -= StateChanged; State.CanRefresh = false; } }