MVC Pagination Help with query string
I'm attempting to put together a very simple application using ASP.NET MVC that shows news articles and paginates them. I'm sort of half-way there but need some help sorting out the pagination and getting it to work with the search query. This is NOT a duplication of this question (Homework) MVC Pagination Help as it deals with keeping the search query when using the pagination and was recommended to start a new question.
Here is my HomeController:
public ActionResult Index(String query, int? page)
{
// limit the number of articles per page
const int pageSize = 4;
// build the query
var ArticleQuery = from a in _db.ArticleSet select a;
// check if their is a query
if (!string.IsNullOrEmpty(query))
{
ArticleQuery = ArticleQuery.Where(a => a.headl开发者_开发技巧ine.Contains(query));
}
// orders the articles
var OrderedArticles = ArticleQuery.OrderByDescending(a => a.posted);
// takes the ordered articles and paginates them
//var paginatedArticles = new PaginatedList(OrderedArticles.Skip((page ?? 0) * pageSize).Take(pageSize), page ?? 0, pageSize);
var paginatedArticles = new PaginatedList<Article>(OrderedArticles, page ?? 0, pageSize);
// return the paginated articles to the view
return View(paginatedArticles);
}
The idea is that the Controller shows 4 items per page will order them by date. Here is the View I have for the Index method:
<ul id="pagination">
<% if (Model.PreviousPage) { %>
<li><%= Html.ActionLink("<< First Page", "Index")%></li>
<li><%= Html.ActionLink("<< Previous Page", "Index", new { page=(Model.PageIndex-1) }) %></li>
<% } %>
<% if (Model.NextPage) { %>
<li><%= Html.ActionLink("Next Page >>", "Index", new { page = (Model.PageIndex + 1) })%></li>
<li><%= Html.ActionLink("Last Page >>", "Index", new { page = (Model.TotalPages - 1) })%></li>
<% } %>
</ul>
The idea is that these two pagination links will only show if the conditions are true.
Finally here is the PaginatedList class for the pager:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace NewsApp.Models
{
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);
}
}
}
NOTE: I' don't want to use any 3rd party components like MVCContrib etc as this is for a University assignment so would defeat the purpose.
The pagination works fine now but when I do a search and have e.g. /?query=test I want to be able to page the results, at the moment they get lost. I'm presuming I'm going to need something such as /?query=test&page=1
Thanks.
The querystring you presented should work (try it directly in the browser to make sure).
Where you'll have an issue is when someone clicks the navigation links because the query
parameter isn't accounted for in your Html.ActionLink
calls. As this is homework I'll leave that as an exercise for the reader = p
Honestly, though. You should be able to figure it out from there. If not comment and I'll chime in again.
-cheers
update
So here is what you currently have your next link:
<%= Html.ActionLink("Next Page >>", "Index", new { page = (Model.PageIndex + 1) })%>
What you need to do is add query as another parameter to the ActionLink. However before you do that you need to capture the query string somewhere in your model. The dirty way of doing this is adding the query value to the ViewData and passing it that way; the clean way is adding a variable to your paginatedList class to hold the current query and setting it in the model. i.e
ViewData["query"] = query;
Or if you choose the model route:
paginatedList.Query = query;
Then you could do something like the following:
<%= Html.ActionLink("Next Page >>", "Index", new { Page = (Model.PageIndex + 1), query = ViewData["query"] /*or Model.Query */ })%>
I'm not sure how you re-setup your routing, but something similar to the above should work. You could also cache the IQueryable
object, or even just the string query itself, but that's a whole other layer of abstraction.
精彩评论