My controller class contains
var Paged = new PaginatedList<Products>(SideBar, page ?? 0, pageSize);
if (Request.IsAjaxRequest())
{
return PartialView("~/Views/Shared/_Grid.cshtml", Paged);
}
return View(Paged);
the PaginatedList is
public class PaginatedList<T> : List<T>
{
public int PageIndex { get; private set; }
public int PageSize { get; private set; }
public int TotalCount { get; private set; }
public int TotalPages { get; private set; }
public PaginatedList(IQueryable<T> source, int pageIndex, int pageSize)
{
PageIndex = pageIndex;
PageSize = pageSize;
TotalCount = source.Count();
TotalPages = (int)Math.Ceiling(TotalCount / (double)PageSize);
this.AddRange(source.Skip(PageIndex * PageSize).Take(PageSize));
}
public bool HasPreviousPage
{
get
{
return (PageIndex > 0);
}
}
public bool HasNextPage
{
get
{
return (PageIndex + 1 < TotalPages);
}
}
}
And my view is
<div class="pagination-container">
<nav class="pagination">
<ul>
#for (int i = 0; i < Model.TotalPages; i++)
{
<li><a href="#Url.Action("Index", "Home", new { page = i})"
class="#(i == Model.PageIndex ? "current-page" : "")">#(i + 1)</a></li>
}
</ul>
</nav>
<nav class="pagination-next-prev">
<ul>
#if (Model.HasPreviousPage) {
<li></li>
}
#if (Model.HasNextPage) {
<li></li>
}
</ul>
</nav>
<div>
Page #(Model.PageIndex + 1) of #Model.TotalPages
</div>
</div>
One problem with the view above, is that it creates numeric pages equal to the page sizes within model. If the model has 6 pages the result is
What will happen if i have 100 Model.Pages ?
You need to make sure that you separate you're not returning all the data in the model - you return only return the page size, at most, and have a separate property to store the total count.
For instance:
public class PageResult<T> where T : class
{
public PageResult(IEnumerable<T> items, int page = 1, int pageSize = 10)
{
this.Items = items;
this.PageSize = pageSize;
this.PageIndex = page;
this.PaginateData(page);
}
public IEnumerable<T> Items { get; private set; }
public int PageSize { get; private set; }
public int PageIndex { get; private set; }
public int Total { get; private set; }
public int TotalPages
{
get
{
return Math.Max((int)Math.Ceiling((Total / (double)PageSize)), 1);
}
}
private int _MaxPagesToDisplay = 10;
public int MaxPagesToDisplay
{
get { return _MaxPagesToDisplay; }
set { _MaxPagesToDisplay = value; }
}
public int PagesToDisplay
{
get
{
return Math.Min(this.MaxPagesToDisplay, TotalPages);
}
}
public void PaginateData(int page)
{
if(this.Items == null) return;
this.Total = this.Items.Count();
this.Items = this.Items.Skip(this.PageSize * this.PageIndex - 1).Take(this.PageSize);
}
}
This will mean you can return for example 1 million results and set the Total to 1 million, but only insert 10 into the Items collection. You can use Linq to paginate the data into this collection. I added the method PaginateData which does it for you.
Then you can update your view:
#for (int i = 1; i <= Model.PagesToDisplay; i++)
{
<li><a href="#Url.Action("Index", "Home", new { page = i})"
class="#(i == Model.PageIndex ? "current-page" : "")">#(i)</a></li>
}
You can then use the Total field to display the total count on the page.
Related
I have a PaginatedList<T> class inheriting from List<T> in an ASP.NET Core app that my controllers and views use to render paginated content:
public class PaginatedList<T> : List<T>
{
public int PageNumber { get; private set; } = 1; // page index
public int PageSize { get; private set; } = 25; // item count in each page
public int TotalCount { get; private set; } // total items in all pages
public int PageCount { get; private set; } // total page count
public bool HasPreviousPage => PageNumber > 1;
public bool HasNextPage => PageNumber < PageCount;
public int From => PageSize * (PageNumber - 1) + 1; // index of first item in page
public int To => From + Count - 1; // index of last item in page
//Method bodies omitted for brevity
public static async Task<PaginatedList<T>> CreateAsync(
IQueryable<T> source, int pageSize = 25, int pageNumber = 1) {..}
private PaginatedList(
List<T> items, int count, int pageSize = 25, int pageNumber = 1) {..}
}
Code based on this with additional validation.
I have noticed that almost all of my views serving paginated lists have the same page navigation UI. (For all entities in the app like Person, Book, etc.):
#model PaginatedList<Person>
#*View-specific code here...*#
<nav aria-label="Page Navigation">
#if (Model.Count > 1)
{
#* Display the range of entities displayed *#
<div class="text-center text-muted my-2">
<em>Showing #Model.From to #Model.To out of #Model.TotalCount</em>
</div>
}
<ul class="pagination justify-content-center">
#if (Model.HasPreviousPage || Model.HasNextPage)
{
#if (Model.HasPreviousPage)
{
<li class="page-item">
<a asp-controller="Person"
asp-action="Index"
asp-route-repoId="#Model.RepoId"
asp-route-page="#(Model.PageNumber - 1)"
title="Previous" class="page-link" aria-label="Previous">
<span class="sr-only">Previous</span>«
</a>
</li>
}
else
{
<li class="page-item disabled">
<a class="page-link" tabindex="-1">
<span class="sr-only">Previous</span>«
</a>
</li>
}
<li class="page-item active" aria-current="page">
<a class="page-link" href="#">#Model.PageNumber</a>
</li>
#if (Model.HasNextPage)
{
<li class="page-item">
<a
asp-controller="Person"
asp-action="Index"
asp-route-repoId="#Model.RepoId"
asp-route-page="#(Model.PageNumber + 1)" title="Next" class="page-link" aria-label="Next">
<span class="sr-only">Next</span>»
</a>
</li>
}
else
{
<li class="page-item disabled">
<a class="page-link" tabindex="-1">
<span class="sr-only">Next</span>»
</a>
</li>
}
}
</ul>
</nav>
I would like to extract this to a partial view called _PageNav.cshtml. But there are two things I'm not quite sure about:
The PaginatedList<T> class is generic and I cannot have a partial view with a model called PaginatedList<T> with an open generic parameter T. One possible solution I can think of is writing a non-generic interface called IPaginatedList that has all the properties required for page navigation and then have PaginatedList<T> implement it. This is because the navigation UI does not need to know anything about the items in the list. Then I can use IPaginatedList as the model for my partial view:
public interface IPaginatedList
{
public int PageNumber { get; }
public int PageSize { get; }
public int TotalCount { get; }
public int PageCount { get; }
public bool HasPreviousPage { get; }
public bool HasNextPage { get; }
public int From { get; }
public int To { get; }
}
public class PaginatedList<T> : List<T>, IPaginatedList
{
...
}
_PageNav.cshtml:
#model IPaginatedList
#* Navigation UI *#
...
This would kind of solve the first issue.
The second issue is that each view with a paginated list has a different previous and next page link. (the area/controller/action name for the link and different route values):
#* Previous page link *#
<a asp-controller="Persons"
asp-action="Index"
asp-route-repoId="#Model.RepoId"
asp-route-page="#(Model.PageNumber - 1)"
title="Previous"
class="page-link"
aria-label="Previous">
<span class="sr-only">Previous</span>«
</a>
#* Next page link *#
<a asp-controller="Persons"
asp-action="Index"
asp-route-repoId="#Model.RepoId"
asp-route-page="#(Model.PageNumber + 1)"
title="Next"
class="page-link"
aria-label="Next">
<span class="sr-only">Next</span>»
</a>
The above would be the previous and next links for the Index action of PersonsController (Person entity). This would change for another entity like Book.
Should I have a property for each link tag helper argument in my PaginatedList<T> like ControllerName, ActionName, etc.? Is there a better way?
Can this be solved with a custom tag-helper? What am I missing?
I have solution for using tag helpers
public class PaginationTagHelper : TagHelper
{
[HtmlAttributeName("onclick-method-name")]
public string OnClick { get; set; }
[HtmlAttributeName("current-page-index")]
public int CurrentPage { get; set; }
[HtmlAttributeName("end-page")]
public int EndPage { get; set; }
[HtmlAttributeName("start-page")]
public int StartPage { get; set; }
[HtmlAttributeName("total-page-count")]
public int TotalPages { get; set; }
/// <summary>
/// Process
/// </summary>
/// <param name="context"></param>
/// <param name="output"></param>
public override void Process(TagHelperContext context, TagHelperOutput output)
{
var onclickMethodFormat = OnClick + "({0})"; // 0 - pagenumber .
var onclickMethod = string.Empty;
StringBuilder content = new StringBuilder();
content.Append("<nav aria-label=\"Page navigation example\" class=\"pagin-holder clearfix\"> <ul class=\"pagination pagination-sm\">");
if (EndPage > 1)
{
if (CurrentPage > 1)
{
onclickMethod = string.Format(onclickMethodFormat, CurrentPage - 1);
content.Append("<li class=\"page-item\"> Previous</li>");
}
for (var page = StartPage; page <= EndPage; page++)
{
onclickMethod = string.Format(onclickMethodFormat, page);
if (page == CurrentPage)
{
content.Append("<li class=\"page-item active\">").Append(page).Append(" ");
}
else
{
content.Append("<li class=\"page-item\">").Append(page).Append(" ");
}
}
if (CurrentPage < TotalPages)
{
onclickMethod = string.Format(onclickMethodFormat, CurrentPage + 1);
content.Append("<li class=\"page-item\"> Next </li>");
}
}
output.Content.AppendHtml(content.ToString());
}
}
This is my custom pagination class
public class PagingInfo
{
public int PageIndex { get; set; }
public int PageSize { get; set; }
public string SortOrder { get; set; }
public byte SortColumn { get; set; }
public string SortColumnName { get; set; }
public int TotalRecords { get; set; }
public string SearchText { get; set; }
public byte FilterByColumn { get; set; }
public string FilterByColumnName { get; set; }
}
public class Pager
{
public Pager(long totalItems, int? page, int pageSize = 10)
{
// calculate total, start and end pages
var totalPages = (int)Math.Ceiling((decimal)totalItems / (decimal)pageSize);
var currentPage = page != null ? (int)page : 1;
var startPage = currentPage - 5;
var endPage = currentPage + 4;
if (startPage <= 0)
{
endPage -= (startPage - 1);
startPage = 1;
}
if (endPage > totalPages)
{
endPage = totalPages;
if (endPage > 10)
{
startPage = endPage - 9;
}
}
TotalItems = totalItems;
CurrentPage = currentPage;
PageSize = pageSize;
TotalPages = totalPages;
StartPage = startPage;
EndPage = endPage;
}
public long TotalItems { get; set; }
public int CurrentPage { get; set; }
public int PageSize { get; set; }
public int TotalPages { get; set; }
public int StartPage { get; set; }
public int EndPage { get; set; }
}
Added tag helper in view:
<Pagination onclick-method-name="Index" current-page-index="Model.PagingInfo.CurrentPage" end-page="Model.PagingInfo.EndPage"
start-page="Model.PagingInfo.StartPage" total-page-count="Model.PagingInfo.TotalPages"></Pagination>
I giv up to solve this. i dont't know what is wrong with my code, if the problem is instance of object, i tried to give my pagging class an instance but still no clue.
This is my index class;
<DataGridComponent TItem="Employee"
DataItems="listEmployee"
Columns="columnDefinitions"
Paging="#(new PagingConfig {
Enabled = true,
CustomPager = true,
PageSize = 3
})">
<CustomPager>
<button class="btn btn-primary" #onclick="PrevPage"> Prev </button>
<span> Page
<input type="number" min="1"#bind-value="#DataGrid.currentPageNumber"/>
of #DataGrid.MaxPageNumber </span>
<button class="btn btn-primary" #onclick="NextPage"> Next </button>
</CustomPager>
</DataGridComponent>
#code{
private DataGridComponent<Employee> DataGrid;
private List<Employee> listEmployee;
private List<ColumnDefinition> columnDefinitions;
protected override void OnInitialized()
{
base.OnInitialized();
Initialize();
}
private void PrevPage()
{
DataGrid.GoToPrevPage();
}
private void NextPage()
{
DataGrid.GoToNextPage();
}
this is my DataGrid class
<div class="level">
<div class="level-left"></div>
<div class="level-right">
<div class="level-item">
#if (Paging != null && Paging.Enabled)
{
#if (Paging.CustomPager)
{
#CustomPager
}
else
{
<span #onclick="GoToPrevPage"><b><</b>Prev</span>
<span> #currentPageNumber of #Paging.MaxPageNumber(DataItems.Count)
</span>
<span #onclick="GoToNextPage"><b>Next></b></span>
}
}
</div>
</div>
</div>
#code {
[Parameter]
public int currentPageNumber { get; set; } = 1;
[Parameter]
public List<TItem> DataItems { get; set; }
[Parameter]
public List<ColumnDefinition> Columns { get; set; }
[Parameter]
public PagingConfig Paging { get; set; } = new PagingConfig();
[Parameter]
public RenderFragment CustomPager { get; set; }
public void GoToPrevPage()
{
currentPageNumber = Paging.PrevPageNumber(currentPageNumber);
}
public void GoToNextPage()
{
currentPageNumber = Paging.NextPageNumber(currentPageNumber, DataItems.Count);
}
public int MaxPageNumber { get => Paging.MaxPageNumber(DataItems.Count); }
}
and this is my my pagingconfig
public class PagingConfig
{
public bool Enabled { get; set; }
public int PageSize { get; set; }
public bool CustomPager { get; set; }
public int NumOfItemsToSkip(int pageNumber)
{
if (Enabled)
{
return (pageNumber - 1) * PageSize;
}
else
return 0;
}
public int NumOfItemsToTake(int totalItemCount)
{
if (Enabled)
{
return PageSize;
}
return totalItemCount;
}
public int PrevPageNumber(int currentPageNumber)
{
if (currentPageNumber > 1)
return currentPageNumber - 1;
else
return 1;
}
public int NextPageNumber(int currentPageNumber, int totalItemsCount)
{
if (currentPageNumber < MaxPageNumber(totalItemsCount))
{
return currentPageNumber + 1;
}
else
{
return currentPageNumber;
}
}
public int MaxPageNumber(int totalItemcount)
{
int maxPageNumber;
double numberOfPage = (double)totalItemcount / (double)PageSize;
if (numberOfPage == Math.Floor(numberOfPage))
{
maxPageNumber = (int)numberOfPage;
}
else
{
maxPageNumber = (int)numberOfPage + 1;
}
return maxPageNumber;
}
}
}
the problem is, when i tried to set enabled into true, the pagging config should get the value of true from index. But it's said not set the instance object yet. i tried to put in, the new Pagging instance into grid component but still no clue :(
DataGrid needs to be assigned. I think you want this:
<DataGridComponent #ref="DataGrid" TItem="Employee" ...>
...
</DataGridComponent>
the reference is to the variable in this line:
private DataGridComponent<Employee> DataGrid;
It's just the #ref="DataGrid" missing in the markup of your DataGridComponent. Therefore, your private DataGrid variable is null.
In Index.razor you set up a DataGridComponent instance in Razor and then declare another one in the code section private DataGridComponent<Employee> DataGrid. These are two unlinked instances of DataGridComponent. To reference DataGrid to your razor declared version you need to use #ref as below.
<DataGridComponent TItem="Employee"
DataItems="listEmployee"
Columns="columnDefinitions"
#ref = "this.DataGrid"
Paging="#(new PagingConfig {
Enabled = true,
CustomPager = true,
PageSize = 3
})">
I'm new to C# and I try to find a way to pass a generic delegate to a constructor.
When calling a show endpoint, if there is pagination, the endpoint should return a Page instance. When creating the Page instance, the delegate method should be passed as one of constructor parameters. ShowsEndpoints will host many endpoints and many of these endpoints use pagination. I want to use only one class to handle all endpoints.
public partial class ShowsEndpoints : Endpoint
{
public Func<Task<IEnumerable<object>>> FetchPopularShowsAsyncDelegate;
public Func<Task<IEnumerable<object>>> FetchTrendingShowsAsyncDelegate;
public Func<Task<IEnumerable<object>>> FetchMostWatchedShowsAsyncDelegate;
public async Task<IEnumerable<object>> FetchPopularShowsAsync(int page = 1, int limit = 20)
{
return await SendAsync(new PopularShowsRequest(page, limit));
}
public async Task<IEnumerable<object>> FetchTrendingShowsAsync(int page = 1, int limit = 20)
{
return await SendAsync(new TrendingShowsRequest(page, limit));
}
public async Task<IEnumerable<object>> FetchMostWatchedShowsAsync(int page = 1, int limit = 20)
{
return await SendAsync(new MostWatchedShowsRequest(page, limit));
}
}
Page class which will call the delegate to fetch the next page if there is a next page.
public class Page<TItem, TDelegate>
{
private TDelegate _delegateCommand;
public int CurrentPage { get; }
public int TotalPages { get; }
public int PageItemsCount { get; }
public int TotalItemsCount { get; }
public IEnumerable<TItem> Items { get; }
public Page(int page, int totalPages, int itemsCount, int totalItemsCount, IEnumerable<TItem> items, TDelegate delegateCommand)
{
CurrentPage = page;
TotalPages = totalPages;
PageItemsCount = itemsCount;
TotalItemsCount = totalItemsCount;
Items = items;
_delegateCommand = delegateCommand;
}
public bool HasNext()
{
return CurrentPage <= TotalPages;
}
public bool HasPrevious()
{
return CurrentPage >= 1;
}
public Page<TItem, TDelegate> Next()
{
// call _delegateCommand to fetch the next page items
}
public Page<TItem, TDelegate> Previous()
{
// call _delegateCommand to fetch the previous page items
}
}
Is it possible ?
Thank you.
EDIT
I have updated my classes code in order to understand better my question. I have 3 endpoints associated with their delegates and I want the Page class to use any of these 3 delegates with the same code to avoid duplication. So _delegateCommand can be FetchPopularShowsAsyncDelegate, FetchTrendingShowsAsyncDelegate or FetchMostWatchedShowsAsyncDelegate.
I'm not sure if I've got the purpose of _delegateCommand right - I guess it should be the function returning IEnumerable<TItem>. If so, then you can declare it precisely like that, and then you won't have to introduce another generic parameter:
public class Page<TItem>
{
private Func<IEnumerable<TItem>>_delegateCommand;
public int CurrentPage { get; }
public int TotalPages { get; }
public int PageItemsCount { get; }
public int TotalItemsCount { get; }
public IEnumerable<TItem> Items { get; }
public Page(int page, int totalPages, int itemsCount,
int totalItemsCount, IEnumerable<TItem> items,
Func<IEnumerable<TItem>> delegateCommand)
{
CurrentPage = page;
TotalPages = totalPages;
PageItemsCount = itemsCount;
TotalItemsCount = totalItemsCount;
Items = items;
_delegateCommand = delegateCommand;
}
public bool HasNext()
{
return CurrentPage <= TotalPages;
}
public bool HasPrevious()
{
return CurrentPage >= 1;
}
}
I implement in my WCF Services tha pagination throught Data Service but not work, the code from the activation is:
public class Profit : DataService<ProfitEntities>
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config)
{
// Set page size defaults for the data service.
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
config.SetEntitySetPageSize("artEntities", 1);
}
}
I use EF 6 + Linq
I retrieve all my Product indeed without a problem but I need the pagination beacuse is a large data.
Thanks you
Code of my Query:
public List<Product> GetAllProduct()
{
ProfitEntities context = new ProfitEntities();
List<Product> product = new List<Product>();
foreach (artEntities art in context.art)
{
product.Add(new Product
{
coArt = art.co_art.Trim(),
desArt = art.art_des.Trim(),
stockAct = Convert.ToDecimal(art.stock_act),
precVta1 = Convert.ToDecimal(art.prec_vta1),
anulado = art.anulado
});
}
if (product.Count > 0)
{
return product;
}
else
throw new Exception("Imposible conseguir lista de Articulos");
}
Thanks you for your help.
I found other way to make the pagination to WCF Services...
I used a two class found in other proyect from MVC and change to my purpose...
Interface IPagedList
public interface IPagedList<T> : IList<T>
{
int PageCount { get; }
int TotalItemCount { get; }
int PageIndex { get; }
int PageNumber { get; }
int PageSize { get; }
bool HasPreviousPage { get; }
bool HasNextPage { get; }
bool IsFirstPage { get; }
bool IsLastPage { get; }
}
Paged Class
public class PagedList<T> : List<T>, IPagedList<T>
{
public PagedList(IEnumerable<T> source, int index, int pageSize, int? totalCount = null)
: this(source.AsQueryable(), index, pageSize, totalCount)
{
}
public PagedList(IQueryable<T> source, int index, int pageSize, int? totalCount = null)
{
if (index < 0)
throw new ArgumentOutOfRangeException("index", "Value can not be below 0.");
if (pageSize < 1)
throw new ArgumentOutOfRangeException("pageSize", "Value can not be less than 1.");
if (source == null)
source = new List<T>().AsQueryable();
var realTotalCount = source.Count();
PageSize = pageSize;
PageIndex = index;
TotalItemCount = totalCount.HasValue ? totalCount.Value : realTotalCount;
PageCount = TotalItemCount > 0 ? (int)Math.Ceiling(TotalItemCount / (double)PageSize) : 0;
HasPreviousPage = (PageIndex > 0);
HasNextPage = (PageIndex < (PageCount - 1));
IsFirstPage = (PageIndex <= 0);
IsLastPage = (PageIndex >= (PageCount - 1));
if (TotalItemCount <= 0)
return;
var realTotalPages = (int)Math.Ceiling(realTotalCount / (double)PageSize);
if (realTotalCount < TotalItemCount && realTotalPages <= PageIndex)
AddRange(source.Skip((realTotalPages - 1) * PageSize).Take(PageSize));
else
AddRange(source.Skip(PageIndex * PageSize).Take(PageSize));
}
#region IPagedList Members
public int PageCount { get; private set; }
public int TotalItemCount { get; private set; }
public int PageIndex { get; private set; }
public int PageNumber { get { return PageIndex + 1; } }
public int PageSize { get; private set; }
public bool HasPreviousPage { get; private set; }
public bool HasNextPage { get; private set; }
public bool IsFirstPage { get; private set; }
public bool IsLastPage { get; private set; }
#endregion
}
My Operation Contract (Class)
private int defaultPageSize = 10;
ProfitEntities context = new ProfitEntities();
public List<Product> GetAllProduct(string value)
{
var artprofit = context.art.Include("colores").Include("lin_art").Include("sub_lin").Include("cat_art").ToList();
int? page = Convert.ToInt32(value);
int currentPageIndex = page.HasValue ? page.Value - 1 : 0;
var productListPaged = artprofit.ToPagedList(currentPageIndex, defaultPageSize);
}
I am building a pagination my mvc project and have follew problem.
I did everything for pagination and now need just pass a page information to view data in view.
I have a user control Pagination:
Pagination.ascx:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="Pagination.ascx.cs"
Inherits="PIMP.Web.TestForum.Views.Shared.Pagination" %>
<ul id="pagination-flickr">
<% if (ViewData.Model.HasPreviousPage)
{ %>
<li class="previous"><a href="<%=ViewData.PageActionLink.Replace("%7Bpage%7D", (ViewData.PageIndex - 1).ToString())%>">
« Previous</a></li>
<% }
else
{ %>
<li class="previous-off">« Previous</li>
<% } %>
<%for (int page = 1; page <= ViewData.Model.TotalPages; page++)
{
if (page == ViewData.Model.PageIndex)
{ %>
<li class="active">
<%=page.ToString()%></li>
<% }
else
{ %>
<li><a href="<%=ViewData.PageActionLink.Replace("%7Bpage%7D", page.ToString())%>">
<%=page.ToString()%></a></li>
<% }
}
if (ViewData.Model.HasNextPage)
{ %>
<li class="next"><a href="<%=ViewData.PageActionLink.Replace("%7Bpage%7D", (ViewData.PageIndex + 1).ToString())%>">
Next »</a></li>
<% }
else
{ %>
<li class="next-off">Next »</li>
<% } %>
</ul>
<ul id="pagination-flickr0">
<li></li>
</ul>
Pagination.ascx.cs:
public partial class PaginationViewData
{
public int PageIndex { get; set; }
public int TotalPages { get; set; }
public int PageSize { get; set; }
public int TotalCount { get; set; }
public string PageActionLink { get; set; }
public bool HasPreviousPage
{
get
{
return (PageIndex > 1);
}
}
public bool HasNextPage
{
get
{
return (PageIndex * PageSize) <= TotalCount;
}
}
}
public partial class Pagination : System.Web.Mvc.ViewUserControl<PaginationViewData>
{
public Pagination()
{
}
}
class PagedList.cs:
namespace PIMP.Web.TestForum.DataObject.Forum
{
public class PagedList<T>: List<T>
{
public PagedList(IQueryable<T> source, int index, int pageSize)
{
this.TotalCount = source.Count();
this.PageSize = pageSize;
this.PageIndex = index;
this.AddRange(source.Skip((index - 1) * pageSize).Take(pageSize).ToList());
int pageResult = 0;
for (int counter = 1; pageResult < this.TotalCount; counter++)
{
pageResult = counter * this.PageSize;
this.TotalPages = counter;
}
}
public PagedList()
{
}
public int TotalPages
{
get;
set;
}
public int TotalCount
{
get;
set;
}
public int PageIndex
{
get;
set;
}
public int PageSize
{
get;
set;
}
public bool HasPreviousPage
{
get
{
return (PageIndex > 1);
}
}
public bool HasNextPage
{
get
{
return (PageIndex * PageSize) <= TotalCount;
}
}
}
public static class Pagination
{
public static PagedList<T> ToPagedList<T>(this IQueryable<T> source, int index, int pageSize)
{
return new PagedList<T>(source, index, pageSize);
}
public static PagedList<T> ToPagedList<T>(this IQueryable<T> source, int index)
{
return new PagedList<T>(source, index, 10);
}
}
}
in View I am doing following:
<% Html.RenderPartial("Pagination", new NISE.Web.TestForum.Views.Shared.PaginationViewData()
{
PageIndex = ViewData.Model.PageIndex,
TotalPages = ViewData.Model.TotalPages,
PageActionLink = Url.Action("Forum", "Thread", new { id = this.Model.Id, page = "{page}" }),
TotalCount = ViewData.Model.TotalCount,
PageSize = ViewData.Model.PageSize
}, null);%>
I dont know what I should do in my controller.
How can I pass Page Information to the ViewData?
My controller looks like that, can you help me to extend it??
[HttpGet]
[ValidateInput(false)]
public ActionResult Thread(Guid id)
{
try
{
ThreadModel model = new ThreadModel(id);
model.IncreaseHitCount();
PagedList<ListView> list = new PagedList<ListView>();
list.PageIndex = 0;
list.PageSize = 0;
list.TotalCount = 0;
list.TotalPages = 0;
return View(model);
}
catch (Exception ex)
{
bool rethrow = ExceptionHelper.Handle(ex, "Business Logic");
if (rethrow)
{
throw;
}
}
return View();
}
Well, I did it like this:
I created a "view-model" of (my custom) data grid which contains infos about the current page, page size, etc.
it looks like this:
using System.Collections.Generic;
public class GridContent<T>
{
public IEnumerable<T> Data { get; set; }
public int PageIndex { get; set; }
public int TotalPages { get; set; }
public int TotalItems { get; set; }
}
in the controller I then return the following:
return View(new GridContent<Entity>()
{
Data = entityEnumeration, // your actual data
PageIndex = pageIndex,
TotalItems = totalItems,
TotalPages = totalItems / pageSize + 1
});
and finally on the view
<%# Page Title="SomeTitle" Language="C#" Inherits="System.Web.Mvc.ViewPage<GridContent<Entity>>" %>
Now you can access the pagination information as well as the data using the wrapper model / class GridContent.
Hope this helps.