SportsStore是《精通ASP.NET MVC3框架(第三版)》中演示的MVC專案,在該專案中涵蓋了MVC的眾多方面,包括:使用DI容器、URL優化、導航、分頁、購物車、訂單、產品管理、影象上傳......是不錯的MVC實踐專案,但該專案不是放在多層框架下開發的,離真實專案還有一段距離。本系列將嘗試在多層框架下實現SportsStore專案,並用自己的方式實現一些功能。
本篇為系列第四篇,包括:
■ 7、新增分頁
7、新增分頁
關於分頁,是一系列的a標籤,可以通過擴充套件HtmlHelper來實現。產生分頁a標籤的大致思路為:
1、擴充套件方法需要遍歷迴圈所有頁數,而所有頁數是由"總記錄數/頁容量",再經過計算得到。
2、可以把總記錄數、頁容量、所有頁數等封裝成一個類提供給擴充套件方法。
3、而包含總記錄數、頁容量、所有頁數等這個類例項,當然是由控制器方法提供。
建立PagingInfo來包裝分頁相關資訊:
using System; namespace MySportsStore.WebUI.Models { public class PagingInfo { public int TotalItems { get; set; } public int ItemsPerPage { get; set; } public int CurrentPage { get; set; } public int TotalPages { get { return (int)Math.Ceiling((decimal) TotalItems/ItemsPerPage); } } } }
關於CurrentPage屬性,擴充套件方法會根據它來確定是否要給a標籤新增一個表示選中、當前頁的css屬性。
擴充套件方法遍歷迴圈所有頁數,產生數字a標籤,並根據PagingInfo的CurrentPage屬性來判斷是否要給a標籤加上一個用來表示選中、當前頁的屬性:
using System; using System.Text; using System.Web.Mvc; using MySportsStore.WebUI.Models; namespace MySportsStore.WebUI.HtmlHelpers { public static class PagingHelpers { public static MvcHtmlString PageLinks(this HtmlHelper html, PagingInfo pagingInfo, Func<int, string> pageUrl) { StringBuilder result = new StringBuilder(); for (int i = 1; i <= pagingInfo.TotalPages; i++) { TagBuilder tag = new TagBuilder("a"); tag.MergeAttribute("href", pageUrl(i)); tag.InnerHtml = i.ToString(); if (i == pagingInfo.CurrentPage) { tag.AddCssClass("selected"); } result.Append(tag.ToString()); } return MvcHtmlString.Create(result.ToString()); } } }
以上的pageUrl是一個委託,輸入頁面,輸出一個包含查詢字串的URL。
而新增的擴充套件方法需要在Views資料夾下的Web.config中註冊後,才能在檢視頁中使用:
<system.web.webPages.razor> <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> <pages pageBaseType="System.Web.Mvc.WebViewPage"> <namespaces> ...... <add namespace="MySportsStore.WebUI.HtmlHelpers" /> </namespaces> </pages> </system.web.webPages.razor>
當然,分頁是有關Product的分頁,在顯示Product列表的檢視頁上,除了分頁,還有一個Product的集合,於是,我們可以把分頁和Product的集合整合成一個檢視模型:
using System.Collections.Generic; using MySportsStore.Model; namespace MySportsStore.WebUI.Models { public class ProductsListViewModel { public IEnumerable<Product> Products { get; set; } public PagingInfo PagingInfo { get; set; } } }
Product控制器的List方法職責很明確:就是根據前臺檢視傳遞過來表示當前頁的page變數,產生一個ProductsListViewModel的例項,傳遞給前臺檢視:
using System.Web.Mvc; using MySportsStore.IBLL; using MySportsStore.WebUI.Models; using Ninject; namespace MySportsStore.WebUI.Controllers { public class ProductController : BaseController { [Inject] public IProductService ProductService { get; set; } public ProductController() { this.AddDisposableObject(ProductService); } public int PageSize = 4; public ViewResult List(int page = 1) { int totalCount = 0; ProductsListViewModel viewModel = new ProductsListViewModel() { Products = ProductService.LoadPageEntities(p => true, p => p.Id, PageSize, page, out totalCount, true), PagingInfo = new PagingInfo(){CurrentPage = page, ItemsPerPage = PageSize, TotalItems = ProductService.Count(p => true)} }; return View(viewModel); } } }
Product/List.cshtml強型別檢視:
@model MySportsStore.WebUI.Models.ProductsListViewModel @{ ViewBag.Title = "List"; Layout = "~/Views/Shared/_Layout.cshtml"; } @foreach (var item in Model.Products) { <div class="item"> <h3>@item.Name</h3> @item.Description <h4>@item.Price.ToString("c")</h4> </div> } <div class="pager"> @Html.PageLinks(Model.PagingInfo, x => Url.Action("List", new {page = x})) </div>
執行,得到如下結果:
讓人欣慰的是:對Prouct列表進行了分頁處理。稍有不足的是:頁面連結以http://localhost/?page2這種形式存在。我們在路由設定中設定如下路由:
routes.MapRoute( null, "Page{page}", new {controller = "Product", action = "List"} ); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Product", action = "List", id = UrlParameter.Optional } );
執行,得到如下結果:
在Views/Shared/_Layout.chstml中佈局頁面,設定CSS,呈現如下頁面:
在Product/List.cshtml檢視頁中,還可以把顯示產品的邏輯放到一個部分檢視中,以便重複利用。在Views/Shared下建立ProductSummary.cshtml強型別部分檢視:
@model MySportsStore.Model.Product <div class="item"> <h3>@Model.Name</h3> @Model.Description <h4>@Model.Price.ToString("c")</h4> </div>
最後,在Product/List.cshtml檢視頁中,在遍歷Product集合的時候,載入部分檢視:
@model MySportsStore.WebUI.Models.ProductsListViewModel @{ ViewBag.Title = "List"; Layout = "~/Views/Shared/_Layout.cshtml"; } @foreach (var item in Model.Products) { Html.RenderPartial("PrductSummary", item); } <div class="pager"> @Html.PageLinks(Model.PagingInfo, x => Url.Action("List", new {page = x})) </div>
至此,完成分頁。
原始碼在這裡。
“MVC專案實踐,在三層架構下實現SportsStore”系列包括: