[翻译]ASP.NET MVC 3 开发的20个秘诀(七)[20 Recipes for Programming MVC 3]:对列表进行排序
议题
现在有一个很大的列表(例如,图书列表),想找到某一项是非常难的。如果针对列表中的某一项进行排序,应该会对查找有所帮助。
解决方案
将书籍清单列表的列标题更新为链接,当链接被点击的时候,将通过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());
}
...
}
}
参考