这是我注册博客园的第一片文章,我想写一下自己最近学习MVC3所看的一本书《Pro.ASP.NET.MVC.3》中所讲的一个SportsStore的例子,这个例子分了很多章来完善SportsStore的不同功能,所以这个系列的文章也会按功能的实现分为很多篇。
本文对原程序有一定的改动,省去了原程序中测试和依赖注入的部分
实现数据的显示
程序构建
首先,创建一个空白的解决方案,起名为SportsStore
添加完空白的解决方案以后,我们就要开始完成我们的程序了。我们需要添加如下的两个项目到我们的解决方案中:
项目名 项目在VS中的项目类型 作 用
SportsStore.Domain 类库 保存域实体和逻辑,通过用Entity
Framework生成的存储库保持联系
SportsStore.WebUI ASP.NET MVC 3 应用程序 保存controller和view,担当程序的UI
添加好后的解决方案如下图:为了方便测试,右键单击SportsStore.WebUI 将它设为启动项
Model
添加域模型:在 SportsStore.Domain下新建一个名为Entities的文件夹,添加一个名为Product的类如下图:
1 namespace SportsStore.Domain.Entities { 2 3 public class Product { 4 public int ProductID { get; set; } 5 public string Name { get; set; } 6 public string Description { get; set; } 7 public decimal Price { get; set; } 8 public string Category { get; set; } 9 } 10 }
在SportsStore.WebUI的Model文件夹下添加类StoreDbContext
1 namespace SportsStore.WebUI.Models 2 { 3 public class StoreDbContext:DbContext 4 { 5 public DbSet<Product> Products { get; set; } 6 } 7 }
在SportsStore.WebUI的Web.config里的<configuration>标签下添加
1 <connectionStrings> 2 <add name="StoreDbContext" connectionString="这里添加你的数据库地址" providerName="System.Data.SqlClient"/> 3 </connectionStrings>
Controller
添加一个空的ProductController到SportsStore.WebUI的Controller文件夹下
对新添加的ProductController代码进行修改,如下:
public class ProductController : Controller { StoreDbContext db = new StoreDbContext(); public ActionResult List() { var product = db.Products; return View(product); } }
View
在View下新建名为Product的文件夹,添加名为List的View
图中红框标注的为要注意的地方
修改List的代码如下:
1 @model IEnumerable<SprotsStore.Domain.Entities.Product> 2 3 @{ 4 ViewBag.Title = "List"; 5 } 6 7 <h2>List</h2> 8 9 @foreach (var p in Model) 10 { 11 <div class="item"> 12 <h3>@p.Name</h3> 13 @p.Description 14 <h4>@p.Price.ToString("c")</h4> 15 </div> 16 }
Routing
这时启动项目还是会报错的,我们需要将原文中的Golbal.asax中的代码
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
改为
new { controller = "Product", action = "List", id = UrlParameter.Optional } // Parameter defaults
这样系统就能找到我们所添加的LIst.cshtml了,然后启动程序
如图就是我们的体育用品商店显示的商品列表(事先添加了数据到数据库里)。
很不好看对不对,照这么列下去,我们的页面会被拉得很长很长,所以我们现在要添加一个为我们的体育用品商店添加一个分页的功能。
实现数据的分页显示
Controller
修改ProductController下的List(),使他能够根据分页信息返回相应的数据。
1 public class ProductController : Controller 2 { 3 StoreDbContext db = new StoreDbContext(); 4 public int PageSize = 4; //定义每页显示4条数据 5 public ActionResult List(int page=1) 6 { 7 //根据ProductID排序,略过(page-1)*4条数据,查找4条数据 8 var product = db.Products.OrderBy(p => p.ProductID).Skip((page - 1) * PageSize).Take(PageSize); 9 return View(product); 10 } 11 }
这时你启动程序的话,只能看到页面显示了4条数据。你可以通过在链接地址后加参数的方式来查看后面的数据http://localhost:3719/?page=2,要看第几页的数据,将page的值改为几就可以了。这样我们的程序就实现了分页显示的功能了,但是客户来到你的商店,他们可不知道你的商店的数据显示需要这么操作滴。所以,为他们添加显式的分页操作按钮就变得非常有必要。下面,我们就来添加显式的分页信息。
Model
为Models文件夹添加一个名为PagingInfo的类,他包含了分页所需的数据信息,如下:
1 public class PagingInfo 2 { 3 //总共有多少条数据 4 public int TotalItems { get; set; } 5 //每页几条数据 6 public int ItemsPerPage { get; set; } 7 //当前页是第几页 8 public int CurrentPage { get; set; } 9 //总共多少页 10 public int TotalPages 11 { 12 get { return (int)Math.Ceiling((decimal)TotalItems / ItemsPerPage); } 13 } 14 }
PagingHelpers
添加了分页信息的类PagingInfo后,我们需要考虑的是如何根据分页信息传回的数据来动态生成相应的页数信息来显示到页面上呢?比如一共10条数据,每页显示两条我们就需要分5页显示,要是每页显示5条的话,那只需显示两页就好了。
在 SportsStore.WebUI 下创建一个名为HtmlHelpers的文件夹,并新建一个名为PagingHelpers的静态类,他将作为HtmlHelper的扩展方法存在。在页面中用@Html.来调用。PagingHelpers的内容如下:
1 public static class PagingHelpers 2 { 3 public static MvcHtmlString PageLinks(this HtmlHelper html, PagingInfo pagingInfo, Func<int, string> pageUrl) 4 { 5 //新建StringBuilder实例result 将他作为最终的html字符串 生成相应的 标签 6 StringBuilder result = new StringBuilder(); 7 //循环遍历pagingInfo.TotalPages 生成相应个数的分页数字:1,2,3.... 8 for (int i = 1; i <= pagingInfo.TotalPages; i++) 9 { 10 //使用TagBuilder创建a标签 11 TagBuilder tag = new TagBuilder("a"); 12 13 //当前a标签的跳转地址 14 tag.MergeAttribute("href", pageUrl(i)); 15 //以数字代表a标签的显示内容 16 tag.InnerHtml = i.ToString(); 17 18 19 if (i == pagingInfo.CurrentPage) 20 tag.AddCssClass("selected"); 21 22 result.Append(tag.ToString()); 23 } 24 25 return MvcHtmlString.Create(result.ToString()); 26 } 27 }
现在就需要将我们的PageLinks添加到View的List.cshtml里去,但是直接添加的话会报错。
无法找到PageLinks的引用,这中情况有两种解决方法。一种是将他的引用“@using SportsStore.WebUI.HtmlHelpers”添加到页面顶部,另一种是找到View文件夹下的Web.config,在<namespaces>下添加命名空间<add namespace="SportsStore.WebUI.HtmlHelpers"/>
到这里我们的功能基本可以实现了,需要在做一下整合。
Model :在model下添加一个名为ProductsListViewModel 的类将产品信息和分页信息结合在一起。
1 public class ProductsListViewModel { 2 3 public IEnumerable<Product> Products { get; set; } 4 public PagingInfo PagingInfo { get; set; } 5 }
Controller:修改ProductController下的List,将产品信息和分页信息同时返回个View
1 public ViewResult List(int page = 1) { 2 3 ProductsListViewModel viewModel = new ProductsListViewModel { 4 Products = repository.Products 5 .OrderBy(p => p.ProductID) 6 .Skip((page - 1) * PageSize) 7 .Take(PageSize), 8 PagingInfo = new PagingInfo { 9 CurrentPage = page, 10 ItemsPerPage = PageSize, 11 TotalItems = repository.Products.Count() 12 } 13 }; 14 return View(viewModel); 15 }
View:修改List.cshtml,通过ProductsListViewModel 获取产品信息和分页信息,添加PageLinks,在页面显示。
1 @model SportsStore.WebUI.Models.ProductsListViewModel 2 3 @{ 4 ViewBag.Title = "List"; 5 } 6 7 <h2>List</h2> 8 9 @foreach (var p in Model.Products) 10 { 11 <div class="item"> 12 <h3>@p.Name</h3> 13 @p.Description 14 <h4>@p.Price.ToString("c")</h4> 15 </div> 16 } 17 <div class="pager"> 18 @Html.PageLinks(Model.PagingInfo, x => Url.Action("List", new {page = x})) 19 </div>
如此,启动程序,可以看到我们的程序可以进行分页显示了
遗留问题修改
改善URL
如上图,这样的url和我们的路由选择并不相符,我们可以在Global.asax中添加一个新的路由,因为路由的选择是从上往下的,所以将以下的路由添加到第一位。
routes.MapRoute( null, "Page{page}", new { Controller = "Product", action = "List" } );
这样我们得到的url如下图
样式的添加
我们的页面还需要添加一点样式
对Views文件夹下的Shared文件夹下的_layout.cshtml的body标签进行如下修改:
1 <div id="header"> 2 <div class="title">SPORTS STORE</div> 3 </div> 4 <div id="categories"> 5 Will put something useful here later 6 </div> 7 <div id="content"> 8 @RenderBody() 9 </div>
为Content文件夹下的Site.css添加以下样式:
1 BODY { font-family: Cambria, Georgia, "Times New Roman"; margin: 0; } 2 DIV#header DIV.title, DIV.item H3, DIV.item H4, DIV.pager A { 3 font: bold 1em "Arial Narrow", "Franklin Gothic Medium", Arial; 4 } 5 DIV#header { background-color: #444; border-bottom: 2px solid #111; color: White; } 6 DIV#header DIV.title { font-size: 2em; padding: .6em; } 7 DIV#content { border-left: 2px solid gray; margin-left: 9em; padding: 1em; } 8 DIV#categories { float: left; width: 8em; padding: .3em; } 9 DIV.item { border-top: 1px dotted gray; padding-top: .7em; margin-bottom: .7em; } 10 DIV.item:first-child { border-top:none; padding-top: 0; } 11 DIV.item H3 { font-size: 1.3em; margin: 0 0 .25em 0; } 12 DIV.item H4 { font-size: 1.1em; margin:.4em 0 0 0; } 13 14 DIV.pager { text-align:right; border-top: 2px solid silver; 15 padding: .5em 0 0 0; margin-top: 1em; } 16 DIV.pager A { font-size: 1.1em; color: #666; text-decoration: none; 17 padding: 0 .4em 0 .4em; } 18 DIV.pager A:hover { background-color: Silver; } 19 DIV.pager A.selected { background-color: #353535; color: White; }
这样我们的体育用品商店就比以前要好看许多了。
添加部分视图
试想如果这些商品的信息我们需要在其他地方也可以重用,那我们该怎么做呢?是不是先要把他分离出来,这就需要我们为程序添加一个部分视图了。
首先,右键单击Views文件夹下的Shared文件夹,添加一个View
然后为这个View起名为ProductSummary,选择类型为Product,重要的是要勾选“Create as a partial view”选项。做完这三步,点击“Add”就好了。
现在修改这个部分视图,如下:
1 <div class="item"> 2 <h3>@Model.Name</h3> 3 @Model.Description 4 <h4>@Model.Price.ToString("c")</h4> 5 </div>
并对List.cshtml的foreach进行修改:
1 @foreach (var p in Model.Products) 2 { 3 Html.RenderPartial("ProductSummary", p); 4 }
好了,这下我们的数据就被分离出来了,以后在什么地方要用到这些商品数据的话,直接用以上代码来调用就好了,是不是很方便呢?
这一章的内容到这里就结束了,来总结一下我们的成果吧!首先,我们实现商品数据的显示,然后发现浏览起来不是很方便,我们有为它添加了分页浏览的功能,穿插其中我们还完成了URL的优化、界面的美化等功能。这是我的第一篇博客,还有很多不足的地方需要完善,希望大家多提宝贵意见,我好不断改进,写出更好的博客来与大家分享!