[转载][翻译]ASP.NET MVC 3 开发的20个秘诀(七)[20 Recipes for Programming MVC 3]:对列表进行排序 – O2DS – 博客园.
议题
现在有一个很大的列表(例如,图书列表),想找到某一项是非常难的。如果针对列表中的某一项进行排序,应该会对查找有所帮助。
解决方案
将书籍清单列表的列标题更新为链接,当链接被点击的时候,将通过Linq针对选中列的内容进行排序(通过再次点击标题链接来切换升序还是降序)。
讨论
与我之前使用过的框架相比添加排序、自动生成视图的过程让我感到有些惊讶。希望在外来的MVC版本中,他可以成为整体框架的一部分。参考 ASP.NET MVC的网站首页上示例,我们需要定义一个Switch语句,每一列排序情况都需要复制一个Case来实现。还好我们的这个案例当中只有五个项需要排序, 情况还不算太坏。如果以后需要针对比如作者或者其他列排序,只需要复制此Case来实现。在下面的示例中,我们将使用Dynamic Linq Library来简化工作。
Linq library 可以从数据库中查询并返回强类型结果。编程工具提供了如智能感知支持和编译时错误检测,我们很多的共奏都将基于这些功能进行操作。
在BooksController控制器和Books、Index视图中添加生成排序支持。以下是Index视图的代码:
@model IEnumerable<MvcApplication4.Models.Book> <h2>@ViewBag.Title</h2> <p> @Html.ActionLink((string)ViewBag.CreateLink, "Create") </p> <table> <tr> <th> @Html.ActionLink((string)ViewBag.TitleDisplay, "Index", new { sortOrder = ViewBag.TitleSortParam }) </th> <th> @Html.ActionLink((string)ViewBag.IsbnDisplay, "Index", new { sortOrder = ViewBag.IsbnSortParam }) </th> <th> @ViewBag.SummaryDisplay </th> <th> @Html.ActionLink((string)ViewBag.AuthorDisplay, "Index", new { sortOrder = ViewBag.AuthorSortParam }) </th> <th> @ViewBag.ThumbnailDisplay </th> <th> @Html.ActionLink((string)ViewBag.PriceDisplay, "Index", new { sortOrder = ViewBag.PriceSortParam }) </th> <th> @Html.ActionLink((string)ViewBag.PublishedDisplay, "Index", new { sortOrder = ViewBag.PublishedSortParam }) </th> <th></th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.Title) </td> <td> @Html.DisplayFor(modelItem => item.Isbn) </td> <td> @Html.DisplayFor(modelItem => item.Summary) </td> <td> @Html.DisplayFor(modelItem => item.Author) </td> <td> @Html.DisplayFor(modelItem => item.Thumbnail) </td> <td> @Html.DisplayFor(modelItem => item.Price) </td> <td> @Html.DisplayFor(modelItem => item.Published) </td> <td> @Html.ActionLink((string)ViewBag.EditLink, "Edit", new { id=item.ID }) | @Html.ActionLink((string)ViewBag.DetailsLink, "Details", new { id = item.ID }) | @Html.ActionLink((string)ViewBag.DeleteLink, "Delete", new { id = item.ID }) </td> </tr> } </table>
在上面这个例子中,修改了以前创建的th标记,使用Html helper将静态文本转换为HTML链接。
接下来,需要修改BookController中的Index方法。此方法将会接受一个新的排序参数,此参数将在Linq执行查询时指定结果排序的列。更会在ViewBag创建一个新的变量存储每个列的排序条件。
Microsoft针对Linq提供了新的免费扩展DynamicQuery类,这个扩展允许在运行的时候动态生成查询语句,可以通过访问 http://msdn2.microsoft.com/en-us/vcsharp/bb894665.aspx 下载到C#版本。下载后解压到硬盘的某个位置,在目录中找到这个文件并添加到项目工程中“~\CSharpSamples\LinqSamples \DynamicQuery\DynamicQuery\Dynamic.cs”。为了更好的组织代码,我们需要在项目工程中创建“Utils”文件夹, 右键单击“Utils”文件夹选择“添加”->“现有项”,然后通过浏览窗口找到这个动态类(或者也可以直接通过拖拽将文件放入“Utils”目 录)。
动态类添加完成后,编辑更新BooksController:
using System; using System.Collections.Generic; using System.Data; using System.Data.Entity; using System.Linq; using System.Linq.Dynamic; using System.Web; using System.Web.Mvc; using MvcApplication4.Models; using MvcApplication4.Resources; namespace MvcApplication4.Controllers { public class BooksController : Controller { private BookDBContext db = new BookDBContext(); // // GET: /Books/ public ViewResult Index(string sortOrder) { #region ViewBag Resources … #endregion #region ViewBag Sort Params // Define the sort orders - if the same link is // clicked twice, reverse the direction from // ascending to descending ViewBag.TitleSortParam = (sortOrder == "Title") ? "Title desc" : "Title"; ViewBag.IsbnSortParam = (sortOrder == "Isbn") ? "Isbn desc" : "Isbn"; ViewBag.AuthorSortParam = (sortOrder == "Author") ? "Author desc" : "Author"; ViewBag.PriceSortParam = (sortOrder == "Price") ? "Price desc" : "Price"; ViewBag.PublishedSortParam = (String.IsNullOrEmpty(sortOrder)) ? "Published desc" : ""; // Default the sort order if (String.IsNullOrEmpty(sortOrder)) { sortOrder = "Published desc"; } #endregion var books = db.Books.OrderBy(sortOrder); return View(books.ToList()); } ... } }
参考