Ошибка Blazor QuickGrid SetCurrentPageIndexAsync
Я использую QuickGrid для userManager.Users в инициализированном асинхронном режиме следующим образом:
itemsQueryable = userManager.Users.AsQueryable();
pagination.TotalItemCountChanged += (sender, eventArgs) => StateHasChanged();
Я использую официальную фильтрацию QuickGrid и примеры пользовательской разбивки по страницам, а также использую userManager.Users Identity в качестве данных. сетка работает хорошо, за исключением двух точек: когда я перетаскиваю второй ползунок для максимальных медалей и когда я использую пользовательскую разбивку по страницам, используя этот метод:
private async Task GoToPageAsync(int pageIndex)
{
await pagination.SetCurrentPageIndexAsync(pageIndex);
}
Что я получаю ошибку:
Error: System.InvalidOperationException: A second operation was started on this context instance before a previous operation completed.
This is usually caused by different threads concurrently using the same instance of DbContext.
For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.
Я пробовал использовать фабрики:
services1.AddDbContextFactory<AppDbContext>(options =>
options.UseSqlServer(appConnectionString,
x => { x.UseNetTopologySuite(); }), ServiceLifetime.Transient);
services1.AddDbContextFactory<IdentityContext>(options =>
options.UseSqlServer(identityConnectionString), ServiceLifetime.Transient);
Но все равно я получаю эту ошибку. Как это решить?
Полный код:
<div class="page-size-chooser mb-3">
Items per page:
<select @bind="@pagination.ItemsPerPage">
<option>2</option>
<option>5</option>
<option>10</option>
<option>20</option>
<option>50</option>
</select>
</div>
<div class="grid table-responsive table table-sm caption-top" style="min-height: 25vh;">
<QuickGrid Items="@FilteredCountries" Pagination="@pagination">
<PropertyColumn Property="@(c => c.UserName)" Sortable="true" Class="user-name">
<ColumnOptions>
<div class="search-box">
<input type="search" autofocus @bind="nameFilter" @bind:event="oninput" placeholder="User name..." />
</div>
</ColumnOptions>
</PropertyColumn>
<PropertyColumn Property="@(c => c.Email)" Sortable="true" Align="Microsoft.AspNetCore.Components.QuickGrid.Align.Center" />
<PropertyColumn Property="@(c => c.CreatedDate)" Sortable="true" Align="Microsoft.AspNetCore.Components.QuickGrid.Align.Center" />
<PropertyColumn Property="@(c => c.LastLoginDate)" Sortable="true" Align="Microsoft.AspNetCore.Components.QuickGrid.Align.Center" />
<TemplateColumn Title="Approved" Sortable="true" SortBy="sortByBool" Align="Microsoft.AspNetCore.Components.QuickGrid.Align.Center">
<div class="flex items-center">
<nobr>
<strong>@(context.IsApproved ? "Yes" : "No")</strong>
</nobr>
</div>
</TemplateColumn>
<PropertyColumn Property="@(c => c.AccessFailedCount)" Sortable="true" Align="Microsoft.AspNetCore.Components.QuickGrid.Align.Center">
<ColumnOptions>
<p>Min: <input type="range" @bind="minMedals" @bind:event="oninput" min="0" max="10" /> <span class="inline-block w-10">@minMedals</span></p>
<p>Max: <input type="range" @bind="maxMedals" @bind:event="oninput" min="0" max="20" /> <span class="inline-block w-10">@maxMedals</span></p>
</ColumnOptions>
</PropertyColumn>
</QuickGrid>
</div>
@*<Paginator Value="@pagination" />*@
<div class="page-buttons">
Page:
@if (pagination.TotalItemCount.HasValue)
{
for (var pageIndex = 0; pageIndex <= pagination.LastPageIndex; pageIndex++)
{
var capturedIndex = pageIndex;
<button @onclick="@(() => GoToPageAsync(capturedIndex))"
class="@PageButtonClass(capturedIndex)"
aria-current="@AriaCurrentValue(capturedIndex)"
aria-label="Go to page @(pageIndex + 1)">
@(pageIndex + 1)
</button>
}
}
</div>
раздел кода:
@code {
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
itemsQueryable = userManager.Users.AsQueryable();
pagination.TotalItemCountChanged += (sender, eventArgs) => StateHasChanged();
}
PaginationState pagination = new PaginationState { ItemsPerPage = 10 };
IQueryable<AppUser> itemsQueryable;
string nameFilter;
int minMedals;
int maxMedals = 20;
GridSort<AppUser> sortByBool = GridSort<AppUser>
.ByAscending(p => p.IsApproved)
.ThenDescending(p => p.LastLoginDate);
IQueryable<AppUser> FilteredCountries
{
get
{
var result = itemsQueryable?.Where(c => c.AccessFailedCount <= maxMedals);
if (!string.IsNullOrEmpty(nameFilter))
{
result = result.Where(c => c.UserName.Contains(nameFilter));
}
if (minMedals > 0)
{
result = result.Where(c => c.AccessFailedCount >= minMedals);
}
return result;
}
}
private async Task GoToPageAsync(int pageIndex)
{
await pagination.SetCurrentPageIndexAsync(pageIndex);
}
private string? PageButtonClass(int pageIndex)
=> pagination.CurrentPageIndex == pageIndex ? "current" : null;
private string? AriaCurrentValue(int pageIndex)
=> pagination.CurrentPageIndex == pageIndex ? "page" : null;
}
1 ответ
Я решил свою проблему, используя:
bool dontrender = false;
private async Task GoToPageAsync(int pageIndex)
{
dontrender = true;
await pagination.SetCurrentPageIndexAsync(pageIndex);
}
protected override bool ShouldRender()
{
base.ShouldRender();
bool shouldrender = !dontrender;
dontrender = false;
return shouldrender;
}
а также удаление:@bind:event="oninput"
от:
<ColumnOptions>
<p>Min: <input type="range" @bind="minMedals" @bind:event="oninput" min="0" max="10" /> <span class="inline-block w-10">@minMedals</span></p>
<p>Max: <input type="range" @bind="maxMedals" @bind:event="oninput" min="0" max="20" /> <span class="inline-block w-10">@maxMedals</span></p>
</ColumnOptions>
К:
<ColumnOptions>
<p>Min: <input type="range" @bind="minMedals" min="0" max="10" /> <span class="inline-block w-10">@minMedals</span></p>
<p>Max: <input type="range" @bind="maxMedals" min="0" max="20" /> <span class="inline-block w-10">@maxMedals</span></p>@*both removed@bind:event="oninput"*@
</ColumnOptions>