.net core 在Blazor中筛选分页列表

.net core 在Blazor中筛选分页列表,.net-core,blazor-server-side,.net Core,Blazor Server Side,我有一个Blazor应用程序,其中有一个列表中的对象列表。我设置了一个寻呼机组件(如下所示),它工作得很好。然后在列表中的一组字段上设置搜索框功能。如果寻呼机在第一页,所有这些都非常有效。任何其他页面和搜索都会显示不可预测的结果。有时甚至无法正确筛选该页面上的项目。任何建议都会有帮助。谢谢 Pager.razor @typeparam TItem <div class="row d-flex col-9"> <div class="justify-content-center

我有一个Blazor应用程序,其中有一个列表中的对象列表。我设置了一个寻呼机组件(如下所示),它工作得很好。然后在列表中的一组字段上设置搜索框功能。如果寻呼机在第一页,所有这些都非常有效。任何其他页面和搜索都会显示不可预测的结果。有时甚至无法正确筛选该页面上的项目。任何建议都会有帮助。谢谢

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);
    }
}
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();
}
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) });
            }
        }
    }
}
编辑

以下是您可能要查找的其他函数和属性:

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();
}
票务名册

@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);
    }
}
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();
}
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) });
            }
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.ComponentModel.DataAnnotations;
使用System.ComponentModel.DataAnnotations.Schema;
使用System.Linq;
使用System.Threading.Tasks;
名称空间TicketingSolutions.Models
{
[表格(“票务名册”)]
公共类票务花名册:IValidatableObject
{
[关键]
公共长票证名册ID{get;set;}
公共int属性ID{get;set;}
公共属性{get;set;}
公共长SellerId{get;set;}
公共用户卖方{get;set;}
公共bool IsActive{get;set;}
public DateTime ValidFrom{get;set;}
公共日期时间?有效到{get;set;}
public DateTime CreatedOn{get;set;}
public long CreatedBy{get;set;}
公共日期时间修饰符{get;set;}
public long ModifiedBy{get;set;}
公共IEnumerable验证(ValidationContext ValidationContext)
{

if(ValidTo有点难理解,因为有一些外部方法在本例中没有显示(编辑可能是为了清晰?)但是,您似乎在使用寻呼机.razor之外的东西来指示分页的工作方式。赠品是
DisplayChanged
事件回调。我可以建议您通过消除顾虑来解决这个问题,这样您就可以让一切正常工作。(根据您拥有的,我可以让它运行得相当快)

首先,让我们设置寻呼机,使其只处理分页信息,并在一个自包含、可重用的组件中包含它自己的所有逻辑。给它一个
TItem
列表和一个
RenderFragment
,它知道该做什么

@typeparam-TItem
@如果(列表!=null)
{
@foreach(显示列表中的变量项)
{
@儿童内容(项目)
}
}
@如果(PageCount>1&&List.Count>PageSize)
{
…这里什么都没有改变,为了简洁起见被删除了。。。
}
10
25
50
@代码{
[参数]
公共列表{get;set;}
public List DisplayList{get;set;}=new List();
[参数]
公共RenderFragment ChildContent{get;set;}
//[参数]
//公共操作DisplayChanged{get;set;}
//[参数]
//呈现的公共操作{get;set;}
私有int PageSize{get;set;}=10;
private int CurrentPage{get;set;}=1;
私有int StartIndex{get;set;}
私有int FinishIndex{get;set;}
private int PageCount{get;set;}
//受保护的覆盖无效OnAfterRender(布尔firstRender)
//{
//base.OnAfterRender(firstRender);
//呈现?.Invoke(真);
//}
私有void ChangePageSize(changeventargs e)
{
PageSize=int.Parse(例如Value.ToString());
更改页面(1);
}
私有void changesplay()
{
显示列表=列表
.Skip((当前页面-1)*页面大小)
.Take(页面大小)
.ToList();
}
受保护的覆盖无效OnParametersSet()
{
//编辑
更改页面(1);
}
受保护的无效更改页(整版页)
{
当前页面=第页;
重置索引();
ChangeDisplay();
}
私有void ResetIndex()
{
PageCount=List.Count/PageSize;
如果(List.Count%PageSize>0)
{
PageCount++;
}
StartIndex=Math.Max(当前第5页,第1页);
FinishIndex=Math.Min(当前页面+5,页面计数);
}
}
您将看到@code块中的一些内容被注释掉了。您不需要这些内容来实现此功能。我们将在一分钟后在父组件中处理初始列表中的值。您将看到一个
RenderFragment
参数,以及一个非参数的
DisplayList
的新属性。您还会注意到在marku中p、 我们有一个
@foreach
块为
DisplayList
属性中的每个项目呈现一个
RenderFragment
实例。如果您遵循
onparameters set
方法的逻辑和您的处理程序来单击页码和箭头,您将看到我们正在创建和呈现的子列表ode>List
参数,该参数基于页数和页码,这就是所呈现的全部内容。该组件现在负责对给定列表中的项目进行分页,并且除了要呈现的列表之外,它没有要运行的外部依赖项,以及关于如何以
RenderFragment
的形式呈现每个项目的说明

接下来,在父组件中,我们设置对寻呼机的调用,如下所示:


@context.FirstName@context.LastName在@context.Role中
您可以随意设置,我使用了
标记进行说明,但如果您需要更深入的信息,请按照说明创建表格、列表等。该组件现在接受
标记之间的子内容,并为其自己的分页列表中的每个项目呈现1

到目前为止,我们已经将寻呼机的逻辑与页面的其余部分解耦,因此现在它只是一个渲染工具,而寻呼机的逻辑是内部的。现在我们可以将重点放在过滤和伪造上