gpt4 book ai didi

.net-core - 在 Blazor 中过滤分页列表

转载 作者:行者123 更新时间:2023-12-04 10:07:28 25 4
gpt4 key购买 nike

我有一个 Blazor 应用程序,其中有一个列表中的对象列表。我设置了一个 Pager 组件(如下所示),效果很好。然后我在列表中的一组字段上设置搜索框功能。如果 Pager 位于第一页,所有这些都非常有效。任何其他页面和搜索都会显示不可预测的结果。有时甚至无法正确过滤该页面上的项目。任何意见将是有益的。谢谢。

Pager.razor

@typeparam TItem

<div class="row d-flex col-9">
<div class="justify-content-center">
@if (PageCount > 1 && List.Count > PageSize)
{
<ul class="pagination justify-content-center">
<li><button @onclick="@(() => ChangePage(1))" class="btn">&laquo;</button></li>

@for (var i = StartIndex; i <= FinishIndex; i++)
{
var currentIndex = i;
@if (i == CurrentPage)
{
<li class="page-item active"><span class="btn">@i</span></li>
}
else
{
<li class="page-item"><button class="btn page-link" @onclick="@(() => ChangePage(currentIndex))">@i</button></li>
}
}

<li><button @onclick="@(() => ChangePage(PageCount))" class="btn">&raquo;</button></li>
</ul>
}
</div>
<select class="custom-select offset-1 col-1 ml-auto" bind="@PageSize" @onchange="@(e => ChangePageSize(e))">
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
</select>
</div>

@code {
[Parameter]
public List<TItem> List { get; set; }

public List<TItem> Display { get; set; }

[Parameter]
public Action<List<TItem>> DisplayChanged { get; set; }

[Parameter]
public Action<bool> Rendered { get; set; }

private int PageSize { get; set; } = 10;
private int CurrentPage { get; set; } = 1;
private int StartIndex { get; set; }
private int FinishIndex { get; set; }
private int PageCount { get; set; }

protected override void OnAfterRender(bool firstRender)
{
base.OnAfterRender(firstRender);
Rendered?.Invoke(true);
}

private void ChangePageSize(ChangeEventArgs e)
{
PageSize = int.Parse(e.Value.ToString());
ChangePage(1);
}

private void ChangeDisplay()
{
DisplayChanged?.Invoke(
List
.Skip((CurrentPage - 1) * PageSize)
.Take(PageSize)
.ToList()
);
}

protected override void OnParametersSet()
{
ResetIndex();

ChangeDisplay();
base.OnParametersSet();
}

protected void ChangePage(int page)
{
CurrentPage = page;
ResetIndex();
ChangeDisplay();
}

private void ResetIndex()
{
PageCount = List.Count / PageSize;

if (List.Count % PageSize > 0)
{
PageCount++;
}

StartIndex = Math.Max(CurrentPage - 5, 1);
FinishIndex = Math.Min(CurrentPage + 5, PageCount);
}
}

寻呼机使用 <Pager List="@FilteredUsers" DisplayChanged="@DisplayChanged" Rendered="@PagerRendered" />
搜索功能
<input class="form-control" type="text" @bind-value="@SearchTerm" @bind-value:event="oninput" />
<select class="form-control" @bind-value="@Property" @bind-value:event="onchange">
<option value="FirstName">First Name</option>
<option value="LastName">Last Name</option>
<option value="Role">Role</option>
<option value="Property">Property</option>
</select>

private string searchTerm;

private string SearchTerm
{
get => searchTerm;
set
{
searchTerm = value;
Filter();
}
}

过滤器
private void Filter()
{
switch (Property)
{
case "FirstName":
FilteredUsers = Users.Where(u => u.FirstName.ToLower().Contains(SearchTerm.ToLower())).ToList();
break;
case "LastName":
FilteredUsers = Users.Where(u => u.LastName.ToLower().Contains(SearchTerm.ToLower())).ToList();
break;
case "Role":
FilteredUsers = Users.Where(u => u.Role.ToString().ToLower().Contains(SearchTerm.ToLower())).ToList();
break;
case "Property":
if (string.IsNullOrEmpty(SearchTerm))
{
FilteredUsers = Users;
}
else
{
FilteredUsers = Users.Where(u => TicketingRosters.Any(t => t.Property.PropertyName.ToLower().Contains(SearchTerm.ToLower()) && u.UserId == t.SellerId)).ToList();
}
break;
}
StateHasChanged();
}

编辑

以下是您可能正在寻找的其他功能和属性:
private List<UserDto> Users { get; set; }
private List<UserDto> FilteredUsers { get; set; }
private List<UserDto> Display { get; set; }

private bool IsPagerRendered { get; set; }
private void DisplayChanged(List<UserDto> display)
{
Display = display;
}

private void PagerRendered(bool rendered)
{
IsPagerRendered = rendered;
StateHasChanged();
}

编辑 2 private List<TicketingRoster> TicketingRosters { get; set; } = new List<TicketingRoster>();
UserDto
#nullable enable
using System;
using System.ComponentModel.DataAnnotations;

namespace TicketingSolutions.Models.DTOs
{
public class UserDto
{
public long UserId { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "First name cannot be empty.")]
[StringLength(75, ErrorMessage = "First Name too long. (75 characters)")]
public string? FirstName { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "Last Name cannot be empty.")]
[StringLength(75, ErrorMessage = "Last Name too long. (75 characters)")]
public string? LastName { get; set; }
[StringLength(75, ErrorMessage = "Middle Name too long. (75 characters)")]
public string? MiddleName { get; set; }
[StringLength(150, ErrorMessage = "Title too long. (150 characters)")]
public string? Title { get; set; }
[DataType(DataType.EmailAddress)]
[StringLength(150, ErrorMessage = "Email Address too long. (150 characters)")]
public string? EmailAddress { get; set; }
[RegularExpression(@"((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}", ErrorMessage = "Not a valid phone number format: (xxx) xxx-xxxx")]
[StringLength(50, ErrorMessage = "Phone Number too long. (50 characters)")]
public string? OfficePhone { get; set; }
[RegularExpression(@"((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}", ErrorMessage = "Not a valid phone number format: (xxx) xxx-xxxx")]
[StringLength(50, ErrorMessage = "Phone Number too long. (50 characters)")]
public string? OtherPhone { get; set; }
public Guid? AdUserId { get; set; }
public bool IsActive { get; set; }
public int? RegionId { get; set; }
public Region? Region { get; set; }
public DateTime CreatedOn { get; set; }
public long CreatedBy { get; set; }
public DateTime ModifiedOn { get; set; }
public long ModifiedBy { get; set; }

public Roles Role { get; set; }

public int? RoleId { get; set; }
public CommissionRole? CommissionRole { get; set; }
}
}

票务名单
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;

namespace TicketingSolutions.Models
{
[Table("TicketingRosters")]
public class TicketingRoster : IValidatableObject
{
[Key]
public long TicketingRosterId { get; set; }
public int PropertyId { get; set; }
public Property Property { get; set; }
public long SellerId { get; set; }
public User Seller { get; set; }
public bool IsActive { get; set; }
public DateTime ValidFrom { get; set; }
public DateTime? ValidTo { get; set; }
public DateTime CreatedOn { get; set; }
public long CreatedBy { get; set; }
public DateTime ModifiedOn { get; set; }
public long ModifiedBy { get; set; }

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (ValidTo <= ValidFrom)
{
yield return new ValidationResult("ValidTo cannot be set to a date before or equal to ValidFrom", new[] { nameof(ValidTo) });
}
}
}
}

最佳答案

有点难以理解,因为在这个例子中你没有展示一些外部方法(为了清楚起见可能编辑?)但似乎你正在使用你的 之外的东西。 Pager.razor 指示您的分页工作方式。赠品是 DisplayChanged事件回调。我可以建议你通过打破顾虑来解决这个问题,你可以让一切正常。 (我能够从你拥有的东西中快速运行它)

首先,让我们设置 Pager 以便它所做的只是处理信息分页,并且它包含它自己的所有逻辑,以便在一个自包含的、可重用的组件中执行此操作。给它一个列表 TItem和一个 RenderFragment<TItem>它知道该怎么做。

@typeparam TItem

<div class="row d-flex col-9">
<div class="justify-content-center">

@if (List != null)
{
@foreach (var item in DisplayList)
{
@ChildContent(item)
}
}

@if (PageCount > 1 && List.Count > PageSize)
{

...Nothing here was changed, eliminated for brevity...


}
</div>
<select class="custom-select offset-1 col-1 ml-auto" bind="@PageSize" @onchange="@(e => ChangePageSize(e))">
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
</select>
</div>

@code {
[Parameter]
public List<TItem> List { get; set; }

public List<TItem> DisplayList { get; set; } = new List<TItem>();

[Parameter]
public RenderFragment<TItem> ChildContent { get; set; }

//[Parameter]
//public Action<List<TItem>> DisplayChanged { get; set; }

//[Parameter]
//public Action<bool> Rendered { get; set; }

private int PageSize { get; set; } = 10;
private int CurrentPage { get; set; } = 1;
private int StartIndex { get; set; }
private int FinishIndex { get; set; }
private int PageCount { get; set; }

//protected override void OnAfterRender(bool firstRender)
//{
// base.OnAfterRender(firstRender);
// Rendered?.Invoke(true);
//}

private void ChangePageSize(ChangeEventArgs e)
{
PageSize = int.Parse(e.Value.ToString());
ChangePage(1);
}

private void ChangeDisplay()
{
DisplayList = List
.Skip((CurrentPage -1) * PageSize)
.Take(PageSize)
.ToList();
}

protected override void OnParametersSet()
{
// Edited
ChangePage(1);
}

protected void ChangePage(int page)
{
CurrentPage = page;
ResetIndex();
ChangeDisplay();
}

private void ResetIndex()
{
PageCount = List.Count / PageSize;

if (List.Count % PageSize > 0)
{
PageCount++;
}

StartIndex = Math.Max(CurrentPage - 5, 1);
FinishIndex = Math.Min(CurrentPage + 5, PageCount);
}
}

您会看到@code 块中的一些内容被注释掉了。你不需要这些来让它工作。我们将在一分钟内在 Parent 组件中处理初始列表中的值。你会看到一个 RenderFragment<TItem>参数,以及 DisplayList 的新属性那不是参数。您还会在标记中注意到,我们有一个 @foreach块渲染我们 RenderFragment 的一个实例对于 DisplayList 中的每个项目属性(property)。如果您遵循 OnParametersSet 中的逻辑方法和单击页码和箭头的处理程序,您将看到我们正在创建和呈现 List 的子列表。基于页数和页码的参数,这就是呈现的全部内容。该组件现在负责从给定的列表中分页项目,除了要呈现的列表之外,它没有其他外部依赖项可以运行,以及如何以 RenderFragment<TItem> 的形式呈现每个项目的说明。 .

接下来,在 家长 组件,我们像这样设置对寻呼机的调用:

<Pager TItem="User" List="FilteredUsers">
<h6>@context.FirstName @context.LastName is in @context.Role </h6>
</Pager>

你可以随意设置,我用了 <h6>用于说明的标签,但请按照说明进行操作 here如果你需要更多的深度,创建表格、列表等。这个组件现在接受 <Pager> 之间的子内容。标记并为它自己的分页列表中的每个项目呈现 1 个。

到目前为止,我们已经将分页器的逻辑与页面的其余部分分离,所以现在它只是一个渲染工具,分页逻辑是内部的。现在我们可以专注于过滤而忘记分页。

搜索过滤:
首先,我为搜索“属性”设置了一个初始值,并设置了一个支持字段,如下所示:

private string property = "FirstName";

private string Property
{
get => property;
set
{
property = value;
Filter();
}
}

这现在与下拉起始值一致,因为 <select>仅在更改时更新此内容,并在更改下拉列表时更新搜索结果。

我离开了你的 SearchTerm属性(property)就像你拥有的一样。

现在在 Filter 方法中:

private void Filter()
{
if (string.IsNullOrEmpty(SearchTerm))
{
FilteredUsers = Users;
}
else
{
switch (Property)
{
case "FirstName":
FilteredUsers = Users.Where(u => u.FirstName.ToLower().Contains(SearchTerm.ToLower())).ToList();
break;
case "LastName":
FilteredUsers = Users.Where(u => u.LastName.ToLower().Contains(SearchTerm.ToLower())).ToList();
break;
case "Role":
FilteredUsers = Users.Where(u => u.Role.ToString().ToLower().Contains(SearchTerm.ToLower())).ToList();
break;
case "Property":
FilteredUsers = Users.Where(u => u.Role.ToString().ToLower().Contains(SearchTerm.ToLower())).ToList();
//FilteredUsers = Users.Where(u => TicketingRosters.Any(t => t.Property.PropertyName.ToLower().Contains(SearchTerm.ToLower()) && u.UserId == t.SellerId)).ToList();
break;
default:
FilteredUsers = Users;
break;
}
}
StateHasChanged();
}

现在首先检查搜索值,并返回完整的 Users如果为空则列出。如果没有,那么你进入开关。这些案例都按照我的方式工作,但是您会看到我注释掉了 Where你原来的逻辑。老实说,我对 TicketingRosters 并不熟悉,我可以说你的逻辑在一个我一无所知的领域中,所以你必须自己推理最后一个案例。但是,如果其他一切正常,您现在就可以专注于找到错误的位置。

所以现在 Filter 方法设置了一个过滤列表,Pager 获取整个列表并自行处理分页,并且您已经很好地分离了关注点,因此如果您遇到问题,您知道去哪里寻找。没有正确分页 -> 它在寻呼机中。过滤不正确 -> 它在过滤器逻辑中。

编辑

在 OP 添加 TicketingRoster 之后和 UserDto类定义,我错误地认为我在查询中发现了问题。但是,通过一些来回 OP 清除了 Pager我上面概述的仍然不能正常运行并且查询是正确的,再看之后我清除了 OnParametersSet调用方法 ChnagePage(1) ,这会将当前页面重置为 1 并重置页面计数。我这边的测试证实 OP 的问题与我的原始响应已被清除。

我的第一次编辑包含了很多关于查询结构和理论的内容,我删除了该部分,因为 a) 它不再与本次讨论相关,并且 b) 回顾过去,它可能显得居高临下,尽管那从来不是我的任何时候的意图。

关于.net-core - 在 Blazor 中过滤分页列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61506253/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com