具有分页的ASP.NET MVC搜索表单

时间:2009-11-05 02:10:13

标签: asp.net asp.net-mvc

我不知所措,因为我必须遗漏一些东西。刚刚完成ASP.NET MVC 1.0(WROX),我试图实现一个执行简单搜索的视图,然后在表中呈现结果。然后,我希望能够通过结果进行分页。

所以我有一个来自ListingsController的搜索操作,从FormCollection获取一些值并相应地过滤结果:

        //
    //POST: /Listings/Search
    //      /Listings/Page/2
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Search(FormCollection collection,int? page)
    {
        var listings = listingRepository.GetListings();

        //filter
        if (collection["TypeOfHouse"] != null)
        {
            string[] typeList = collection["TypeOfHouse"].Split(',');

            foreach (string type in typeList)
            {
                listings = from l in listings
                           where l.TypeOfHouse == type
                           select l;
            }
        }

        //display the first page of results
        int pageSize = 25;
        var paginatedListings = new PriviledgeV1.Helpers.PaginatedList<Listing>(listings, 0, pageSize);



        return View("Results", paginatedListings);
    }

最初,结果视图将使用第1页的前25条记录进行渲染。然后我有一个处理“分页”的结果操作:

    public ActionResult Results(int? page)
    {
        int pageSize = 25;
        var listings = listingRepository.GetListings();
        var paginatedListings = new PriviledgeV1.Helpers.PaginatedList<Listing>(listings, page ?? 0, pageSize);

        return View(listings);
    }

麻烦是因为我不再拥有FormCollection,我无法正确过滤结果。因此,如果我尝试使用/ Listings / Results?page = 2从第1页移至第2页,则结果操作将触发,它将返回所有结果,而不是搜索操作中的过滤结果集。

我真的很困惑这里要做什么,以及为什么没有博客/教程解释这一点,这通常标志着我错过了一些东西。

谢谢!

2 个答案:

答案 0 :(得分:5)

我想有几种方法可以尝试实现这一目标。

  1. 通过查询字符串而不是发布传递搜索参数。可以理解的是,对于高级搜索参数来说,这可能会很复杂和混乱
  2. 将POST的结果存储到隐藏元素。让您的分页控制POST每次都执行相同的操作,而不是单独的Results操作。
  3. 将查询参数存储在会话中持久存储的对象中。
  4. 我确信我们可以从那里获得更多创意,但这应该会给你一个开始。您似乎只关心搜索表单中的一个字段TypeOfListing。你应该可以很容易地通过查询字符串来保存它,所以这就是上面的方法#1。


    <强>更新

    这是我为了在客户端维护您的搜索而放在一起的简单内容。该技术涉及三个部分:

    1. 在页面请求之间维护表单。
    2. 使用表单中的隐藏元素管理页面状态。
    3. 让JavaScript拦截您的分页链接,更新页码隐藏元素,然后重新提交表单。
    4. 这是所有各种部分的代码。请注意,我使用jQuery,以防您喜欢其他内容。我捏造了数据源,只是在实际数据中。此外,我还包括PagedList和PaginationHelper。如果你愿意,可以用你自己代替。

      \ Controllers \ HomeController.cs (搜索是相关部分):

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Web;
      using System.Web.Mvc;
      
      namespace MvcApplication2.Controllers
      {
          [HandleError]
          public class HomeController : Controller
          {
              List<String> _data;
      
              public HomeController()
              {
                  _data = new List<String>();
                  _data.Add("Merry");
                  _data.Add("Metal");
                  _data.Add("Median");
                  _data.Add("Medium");
                  _data.Add("Malfunction");
                  _data.Add("Mean");
                  _data.Add("Measure");
                  _data.Add("Melt");
                  _data.Add("Merit");
                  _data.Add("Metaphysical");
                  _data.Add("Mental");
                  _data.Add("Menial");
                  _data.Add("Mend");
                  _data.Add("Find");
              }
      
              public ActionResult Search()
              {
                  Int32 pageNumber, pageSize = 5, total, first;
                  String typeOfListing;
                  PagedList<String> results;
      
                  if (Request.HttpMethod == "GET")
                  {
                      return View();
                  }
      
                  if (!Int32.TryParse(Request.Form["PageNumber"], out pageNumber)) pageNumber = 1;
                  typeOfListing = Request.Form["TypeOfListing"];
      
                  first = (pageNumber - 1) * pageSize;
                  total = (from s in _data
                           where s.Contains(typeOfListing)
                           select s).Count();
                  results = new PagedList<String>(
                                  (from s in _data
                                   where s.Contains(typeOfListing)
                                   select s)
                                   .Skip(first)
                                   .Take(pageSize), 
                                  total, pageNumber, pageSize);
      
      
                      return View(results);
              }
          }
      }
      

      <强> \助手\ PaginationHelper.cs

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Web;
      using System.Text;
      using System.Web.Routing;
      using System.Web.Mvc;
      using System.Web.Mvc.Html;
      
      namespace MvcApplication2.Helpers
      {
          public static class PaginationHelper
          {
              public static String Pager(this HtmlHelper helper, Int32 pageSize, Int32 pageNumber, Int32 total, String actionName, RouteValueDictionary values)
              {
                  StringBuilder output = new StringBuilder();
                  Int32 totalPages = (Int32)Math.Ceiling((Double)total / pageSize);
      
                  if (values == null)
                      values = helper.ViewContext.RouteData.Values;
      
                  if (pageNumber > 1)
                      output.Append(CreatePageLink(helper, values, "< Previous ", pageNumber - 1, pageSize));
      
                  for (Int32 i = 1; i <= totalPages; i++)
                  {
                      if (i == pageNumber)
                          output.Append(i);
                      else
                          output.AppendFormat(CreatePageLink(helper, values, i.ToString(), i, pageSize));
      
                      if (i < totalPages)
                          output.Append(" | ");
                  }
      
                  if (pageNumber < totalPages)
                      output.Append(CreatePageLink(helper, values, " Next >", pageNumber + 1, pageSize));
      
                  return output.ToString();
              }
      
              private static String CreatePageLink(HtmlHelper helper, RouteValueDictionary values, String text, Int32 pageNumber, Int32 pageSize)
              {
                  RouteValueDictionary routeDictionary = new RouteValueDictionary(values);
                  routeDictionary.Add("page", pageNumber);
                  routeDictionary.Add("pageSize", pageSize);
      
                  return helper.ActionLink(text, null, routeDictionary);
              }
          }
      }
      

      <强> \ PagedList.cs

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Web;
      
      namespace MvcApplication2
      {
          public class PagedList<T> : List<T>
          {
              public Int32 TotalCount { get; protected set; }
              public Int32 PageNumber { get; protected set; }
              public Int32 PageSize { get; protected set; }
      
              public PagedList(IEnumerable<T> items, Int32 total, Int32 pageNumber, Int32 pageSize)
                  : base(items)
              {
                  TotalCount = total;
                  PageNumber = pageNumber;
                  PageSize = pageSize;
              }
          }
      }
      

      <强> \视图\主页\ Search.aspx

      <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<PagedList<String>>" %>
      <%@ Import Namespace="MvcApplication2" %>
      <%@ Import Namespace="MvcApplication2.Helpers" %>
      
      <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
          Search
      </asp:Content>
      
      <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
          <script type="text/javascript">
              $(function() {
                  var results = $("#searchResults");
                  if (results && results.children().length > 2) {
                      $("#searchForm").hide();
                      $("#searchResults .pager>a").click(submitForm);
                  }
              });
      
              function submitForm() {
                  var m = this.href.match(/page=(\d+)/i);
                  if (m) {
                      $("#PageNumber").attr("value", m[1]);
                      $("#searchForm").submit();
                  }
                  return false;
              }
          </script>
          <form id="searchForm" action="<%= Url.Action("Search") %>" method="post">
              <input type="hidden" value="1" id="PageNumber" name="PageNumber" />
              <fieldset>
                  <legend>Search</legend>
                  <label for="TypeOfListing">Type of Listing</label>
                  <%= Html.TextBox("TypeOfListing", Request.Form["TypeOfListing"]) %>
                  <input type="submit" id="btnSubmit" name="btnSubmit" value="Search" />
              </fieldset>
          </form>
         <% if (Model != null)
         {
         %>
          <div id="searchResults">
      
              <div class="results-count">Displaying <%=this.Model.Count %> of <%=this.Model.TotalCount %> results. <%=Html.ActionLink("Start a new search", "Search") %>.</div>
              <%
                     foreach (String result in Model)
                     { 
              %>
              <div class="result"><%=result %></div>
      
              <%     }
              %>
      
              <div class="pager"><%= Html.Pager(Model.PageSize, Model.PageNumber, Model.TotalCount, null, null) %></div>
          </div>
          <%
           } 
          %>
      </asp:Content>
      

答案 1 :(得分:0)

基本上按照其他人的建议更改您的表单以执行HTTP GET,然后使用Nuget下载PagedList,并在您的操作方法中使用模型绑定到来自PagedList的HTML帮助函数的提交按钮和页码(并设置路径)使用RouteValuesDictionary的值)。这样一切都会在查询字符串中持久化,这也是您最想要的搜索页面。 MVC将与您的ViewModel类进行协调。我更喜欢使用ViewModel类而不是一堆参数,因为我觉得它更干净,但只是我的$ .02。

我有一个关于here的博客的例子。

另外,我继续posted the code on a different thread