原文:http://www.asp.net/vnext/overview/aspnet-vnext/vc
介绍view components
view components (VCs) 类似于partial views, 但是VCs更加强大. 可以简单的把VC想象成一个mini的控制器.当你认为使用partial太复杂的时候你可以考虑使用VCs,例如:
- 动态导航菜单Dynamic navigation menus
- 标签云(从数据库获取数据)
- 登录面板
- 购物车
- 最近发布的文章
- 博客的其它边栏
VC由两部分组成, 继承自ViewComponent
的类和Razor视图.
View Component类可以通过下面的方式创建:
- 继承
ViewComponent
. - 用
[ViewComponent]
attribute 装饰类, 或者继承在一个被[ViewComponent]装饰的类
. - 创建一个类, 类名以ViewComponent结尾.
和控制器一样VCs必须是public的类.
添加view component类
- 创建一个文件夹名为ViewComponents. View component 类可以包含在任何文件夹下.
- 在ViewComponents 文件夹下常见一个类文件名为PriorityListViewComponent.cs.
- PriorityListViewComponent.cs 内容如下:
using System.Linq; using Microsoft.AspNet.Mvc; using TodoList.Models; namespace TodoList.ViewComponents { public class PriorityListViewComponent : ViewComponent { private readonly ApplicationDbContext db; public PriorityListViewComponent(ApplicationDbContext context) { db = context; } public IViewComponentResult Invoke(int maxPriority) { var items = db.TodoItems.Where(x => x.IsDone == false && x.Priority <= maxPriority); return View(items); } } }
备注:
- 因为类名
PriorityListViewComponent
以ViewComponent 结尾, 在视图中我们可以使用字符串"PriorityList"
. [ViewComponent]
attribute 被使用来改变他的引用名. 例如, 我们有一个类名为XYZ
, 我们应用ViewComponent
attribute:
[ViewComponent(Name = "PriorityList")] public class XYZ : ViewComponent
上面的[ViewComponent]
attribute 告诉view component选择器当查找视图关联的component的使用 使用PriorityList
, 在视图中使用字符串"PriorityList"
来关联相应的类.- component使用构造函数注入.
Invoke 暴露一个方法在相应的视图中被调用, invoke可以包含任意参数
. Invoke对应的异步方法是InvokeAsync
添加 view component view
- 在 ViewsTodo 文件夹下面创建文件夹名为Components. 注意了必须名为Components.
- 在ViewsTodoComponents 文件夹下面创建文件夹名为PriorityList. 这个文件夹的名字必须和view component 类的名字匹配, 或者类名的前缀匹配(如果类名使用
ViewComponent
后缀). 如果你使用了ViewComponent
attribute, 名字必须和attribute 名匹配. - 在 ViewsTodoComponentsPriorityList 文件夹下创建Default.cshtml Razor视图文件 , 添加如下内容:
@model IEnumerable<TodoList.Models.TodoItem> <h3>Priority Items</h3> <ul> @foreach (var todo in Model) { <li>@todo.Title</li> } </ul>
- 在views odoindex.cshtml 文件中调用VC:
@{ ViewBag.Title = "ToDo Page"; } <div class="jumbotron"> <h1>ASP.NET vNext</h1> </div> <div class="row"> <div class="col-md-4"> @if (Model.Count == 0) { <h4>No Todo Items</h4> } else { <table> <tr><th>TODO</th><th></th></tr> @foreach (var todo in Model) { <tr> <td>@todo.Title </td> <td> @Html.ActionLink("Details", "Details", "Todo", new { id = todo.Id }) | @Html.ActionLink("Edit", "Edit", "Todo", new { id = todo.Id }) | @Html.ActionLink("Delete", "Delete", "Todo", new { id = todo.Id }) </td> </tr> } </table> } <div>@Html.ActionLink("Create New Todo", "Create", "Todo") </div> </div> <div class="col-md-4"> @Component.Invoke("PriorityList", 1) </div> </div>
@await Component.InvokeAsync()
是对应的异步方法. 第一个参数是要调用的component的名字. 后面的参数是传到component类的参数.
注意: 一般来说View Component 视图加在ViewsShared 文件夹下, 因为VCs一般没有指定controller.
添加InvokeAsyn component
更新VC类如下:
using System.Linq;
using Microsoft.AspNet.Mvc;
using TodoList.Models;
using System.Threading.Tasks;
namespace TodoList.ViewComponents
{
public class PriorityListViewComponent : ViewComponent
{
private readonly ApplicationDbContext db;
public PriorityListViewComponent(ApplicationDbContext context)
{
db = context;
}
// Synchronous Invoke removed.
public async Task<IViewComponentResult> InvokeAsync(int maxPriority, bool isDone)
{
string MyView = "Default";
// If asking for all completed tasks, render with the "PVC" view.
if (maxPriority > 3 && isDone == true)
{
MyView = "PVC";
}
var items = await GetItemsAsync(maxPriority, isDone);
return View(MyView, items);
}
private Task<IQueryable<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return Task.FromResult(GetItems(maxPriority, isDone));
}
private IQueryable<TodoItem> GetItems(int maxPriority, bool isDone)
{
var items = db.TodoItems.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority);
string msg = "Priority <= " + maxPriority.ToString() +
" && isDone == "