C# 如何在asp.net核心页面中实现分页

C# 如何在asp.net核心页面中实现分页,c#,razor,asp.net-core,C#,Razor,Asp.net Core,我正在用ef学习asp.net核心剃须刀页面。我想用我的表实现分页,我已经检查了本教程 但它只支持pre和next,我已经研究了很长时间,所有的解决方案都与asp.net核心mvc相关,但我使用的是razor页面,我的项目中没有控制器,有什么想法可以实现吗 这就是我想要实现的效果 分页相对简单。有很多图书馆可以为你做这件事,但我已经开始发现它们的麻烦比它们的价值还多 您需要请求中的三条信息(或设置为默认值): 页码(默认为1) 页面大小(通常默认为10,但随您所需) 排序(严格来说不是必需的

我正在用ef学习asp.net核心剃须刀页面。我想用我的表实现分页,我已经检查了本教程

但它只支持pre和next,我已经研究了很长时间,所有的解决方案都与asp.net核心mvc相关,但我使用的是razor页面,我的项目中没有控制器,有什么想法可以实现吗

这就是我想要实现的效果


分页相对简单。有很多图书馆可以为你做这件事,但我已经开始发现它们的麻烦比它们的价值还多

您需要请求中的三条信息(或设置为默认值):

  • 页码(默认为1)
  • 页面大小(通常默认为10,但随您所需)
  • 排序(严格来说不是必需的,但您至少应该按某种方式排序,以保持页面结果的一致性)
  • 页码和大小为您提供了“跳过”和“获取”值:

    然后,您可以通过以下方式获取结果:

    var pageOfResults = await query.Skip(skip).Take(take).ToListAsync();
    
    其中,
    query
    是一个
    IQueryable
    ——直接使用
    DbSet
    ,或者使用
    Where
    子句、
    OrderBy
    等的
    DbSet

    然后,您只需计算项目总数即可计算页面:

    var count = await query.CountAsync();
    
    Pro-Tip,您可以通过执行以下操作并行化两个查询(结果和总计数):

    var resultsTask = query.Skip(skip).Take(take).ToListAsync();
    var countTask = query.CountAsync();
    
    var results = await resultsTask;
    var count = await countTask;
    
    任务返回热状态,或已启动。
    await
    关键字只保留其余代码的继续部分,直到任务完成。因此,如果您等待每一行,它们将以串行方式完成,但如果您先启动这两行,然后等待每一行,它们将以并行方式处理

    无论如何,一旦你有了计数:

    var totalPages = (int)Math.Ceil(Decimal.Divide(count, size));
    var firstPage = 1;
    var lastPage = totalPages;
    var prevPage = Math.Max(page - 1, firstPage);
    var nextPage = Math.Min(page + 1, lastPage);
    
    注意:您可以根据是否分别等于
    firstPage
    lastPage
    来确定是否显示first/previous和last/next按钮


    然后,只需使用这些信息为自己构建一个模型,您就可以将其发送到视图以呈现结果并生成分页HTML。

    您可以使用
    JW.Pager
    NuGet包()

    下面是一个示例razor pages页面模型,它对150个项目的列表进行分页:

    using System.Collections.Generic;
    using System.Linq;
    using Microsoft.AspNetCore.Mvc.RazorPages;
    using JW;
    
    namespace RazorPagesPagination.Pages
    {
        public class IndexModel : PageModel
        {
            public IEnumerable<string> Items { get; set; }
            public Pager Pager { get; set; }
    
            public void OnGet(int p = 1)
            {
                // generate list of sample items to be paged
                var dummyItems = Enumerable.Range(1, 150).Select(x => "Item " + x);
    
                // get pagination info for the current page
                Pager = new Pager(dummyItems.Count(), p);
    
                // assign the current page of items to the Items property
                Items = dummyItems.Skip((Pager.CurrentPage - 1) * Pager.PageSize).Take(Pager.PageSize);
            }
        }
    }
    
    使用System.Collections.Generic;
    使用System.Linq;
    使用Microsoft.AspNetCore.Mvc.RazorPages;
    使用JW;
    命名空间RazorPagesPagination.Pages
    {
    公共类索引模型:PageModel
    {
    公共IEnumerable项{get;set;}
    公共寻呼机{get;set;}
    公共网络(INTP=1)
    {
    //生成要分页的示例项列表
    var dummyItems=Enumerable.Range(1150)。选择(x=>“项”+x);
    //获取当前页面的分页信息
    寻呼机=新寻呼机(dummyItems.Count(),p);
    //将当前项目页指定给items属性
    Items=dummyItems.Skip((Pager.CurrentPage-1)*Pager.PageSize.Take(Pager.PageSize);
    }
    }
    }
    
    这是razor pages页面,包含分页列表和分页器控件的html:

    @page
    @model RazorPagesPagination.Pages.IndexModel
    
    <!-- items being paged -->
    <table class="table table-sm table-striped table-bordered">
        @foreach (var item in Model.Items)
        {
            <tr>
                <td>@item</td>
            </tr>
        }
    </table>                
    
    <!-- pager -->
    @if (Model.Pager.Pages.Any())
    {
        <nav class="table-responsive">
            <ul class="pagination justify-content-center d-flex flex-wrap">
                @if (Model.Pager.CurrentPage > 1)
                {
                    <li class="page-item">
                        <a class="page-link" href="/">First</a>
                    </li>
                    <li class="page-item">
                        <a class="page-link" href="/?p=@(Model.Pager.CurrentPage - 1)">Previous</a>
                    </li>
                }
    
                @foreach (var p in Model.Pager.Pages)
                {
                    <li class="page-item @(p == Model.Pager.CurrentPage ? "active" : "")">
                        <a class="page-link" href="/?p=@p">@p</a>
                    </li>
                }
    
                @if (Model.Pager.CurrentPage < Model.Pager.TotalPages)
                {
                    <li class="page-item">
                        <a class="page-link" href="/?p=@(Model.Pager.CurrentPage + 1)">Next</a>
                    </li>
                    <li class="page-item">
                        <a class="page-link" href="/?p=@(Model.Pager.TotalPages)">Last</a>
                    </li>
                }
            </ul>
        </nav>
    }
    
    @page
    @模型RazorPagesPagination.Pages.IndexModel
    @foreach(Model.Items中的var项)
    {
    @项目
    }
    @if(Model.Pager.Pages.Any())
    {
    
      @如果(Model.Pager.CurrentPage>1) {
    • } @foreach(Model.Pager.Pages中的var p) {
    • } @if(Model.Pager.CurrentPage
    • }
    }

    有关更多详细信息,我在

    上发布了一个完整的教程,其中包含示例项目。我为.net Core Razor页面创建了一个分页taghelper,可以在html标记或appsettings.json中配置它来显示/隐藏prev next、first last按钮、最大显示页面数和更多自定义设置

    安装nuget软件包:

    Install-Package LazZiya.TagHelpers
    
    将taghelper添加到_ViewImports.cshtml

    @addTagHelper *, LazZiya.TagHelpers
    
    最后,将分页控件添加到视图中:

    <paging 
        total-records="Model.TotalRecords" 
        page-no="Model.PageNo"
        query-string-value="@(Request.QueryString.Value)">
    </paging>
    

    使用appsettings.json进行分页配置将有助于获得更干净的html代码,并使您能够在应用程序中一次性更改所有或某些分页标记帮助器上的分页设置

    有关所有设置,请参见实时演示:

    相关文章:

    我将这个问题的一些答案混合在一起,希望它能帮助到一些人

    添加一个
    PagedResultBase
    类(您可以通过添加所需的其他属性来扩展该类):

    添加一个
    PagedResult
    类:

    public class PagedResult<T> : PagedResultBase where T : class
    {
        public ICollection<T> Results { get; set; }
    
        public PagedResult()
        {
            Results = new List<T>();
        }
    }
    
    你完成了:

    var pagedResult = await MyContext.Posts.Where(p => p.Featured == true).GetPagedResultAsync(1, 10);
    

    @鼻出血有相关文件吗?Thanks@Epistaxis我检查了代码,但它看起来需要一个控制器,我找到了很多支持它的包,但我没有控制器,我只使用razor页面。谢谢,我很感激这个答案解释得这么好。回答得好。如果您使用的是EntityFramework,则不能使用Pro提示,因为EF不支持同一上下文中的多个请求。该死!事实上,据我所知,他们只是不鼓励。对并行查询没有真正的支持,因此某些以错误方式堆叠的操作可能会导致问题。然而,在这里,只有一个select和一个count可以并行化,所以不会出现任何问题,最后我检查了一下,这段代码将按原样运行。至少在EF Core 3.x中,您不能在一个上下文中执行两个并行异步任务。他们现在抛出一个异常。
    <paging 
        total-records="Model.TotalRecords" 
        page-no="Model.PageNo"
        query-string-value="@(Request.QueryString.Value)">
    </paging>
    
    <paging 
        total-records="Model.TotalRecords" 
        page-no="Model.PageNo">
    </paging>
    
    public abstract class PagedResultBase
    {
        public int CurrentPage { get; set; }
        public int PageCount { get; set; }
        public int PageSize { get; set; }
        public int RowCount { get; set; }
    }
    
    public class PagedResult<T> : PagedResultBase where T : class
    {
        public ICollection<T> Results { get; set; }
    
        public PagedResult()
        {
            Results = new List<T>();
        }
    }
    
    public static class IQueryableExtensions
    {
        public async static Task<PagedResult<T>> GetPagedResultAsync<T>(this IQueryable<T> query, int currentPage, int pageSize) where T : class
        {
            var skip = (currentPage - 1) * pageSize;
            var take = pageSize;
    
            var rowCount = await query.CountAsync();
            var results = await query.Skip(skip).Take(take).ToListAsync();
    
            var pagedResult = new PagedResult<T> {
                CurrentPage = currentPage,
                PageCount = (int)Math.Ceiling(decimal.Divide(rowCount, pageSize)),
                PageSize = pageSize,
                RowCount = rowCount,
                Results = results
            };
    
            return pagedResult;
        }
    }
    
    var pagedResult = await MyContext.Posts.Where(p => p.Featured == true).GetPagedResultAsync(1, 10);