在ASP.NET MVC 6中,view components (VCs) 功能類似於虛擬檢視,但是功能更加強大。 VCs兼顧了檢視和控制器的優點,你可以把VCs 看作一個Mini 控制器。它負責控制應用中的某一功能模組,例如:
- 動態導航選單
- 標籤雲
- 登入皮膚
- 購物車
- 最近文章
- 部落格側邊欄
假如使用VC 建立了登入皮膚,可以在很多場景中呼叫,例如:
- 使用者沒有登入
- 使用者已登入,需要退出使用其他帳號登入或者管理其他帳號。
- 如果當前登入角色為管理員,渲染管理員登入皮膚
你可以根據使用者的需求獲取資料進行渲染。新增VC到需要該檢視控制元件的頁面。
VC 包含兩部分,類 (一般繼承於ViewComponent) 和呼叫VC類中方法的Razor 檢視。類似於ASP.NET 控制器, VC 可以作為POCO使用,但是更多使用者傾向於使用從 VewComponent中繼承而來的方法和屬性。
VC的建立方式有:
- 繼承ViewComponent.
- 擁有 [ViewComponent] 屬性,或者從擁有 [ViewComponent]屬性派生的類。
- 建立名稱已ViewComponent為字尾的類。
和controllers相同,VCs 必須是公開、非巢狀和非抽象的類。
新增view component 類
1. 建立名為ViewComponents的資料夾,View component 類可以包含在工程中的任何資料夾下。
2. 在ViewComponents 資料夾下建立PriorityListViewComponent.cs 類。.
3. 使用以下程式碼替代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" 從View中引用該類。在後續章節將會進行詳細闡述。
· [ViewComponent] 屬性用於設定引用VC的別名,例如,建立名稱為XYZ的類,我們可以通過以下程式碼設定其引用別名:
[ViewComponent(Name = "PriorityList")] public class XYZ : ViewComponent
· 元件使用構造注入器使資料內容生效,類似於 Todo 控制器的功能。
· 呼叫View中的公開方法,可以傳遞任意數量的引數。在非同步版本中, InvokeAsync是可用的。在後續章節中我們將提及InvokeAsync 和多引數的使用方法。在之前的程式碼中,公開方法的返回值為代辦事項(ToDoItems),優先順序不低於maxPriority。
新增檢視控制元件
1. 在Views\Todo 資料夾下建立Components資料夾,注意這個資料夾需要命名為Components。
2. 在Views\Todo\Components 資料夾下建立PriorityList 資料夾。資料夾名稱必須和view component 類名稱一致。或者類名去除字尾名稱(如果在建立類時遵循慣例使用ViewComponent 作為字尾)。如果使用了ViewComponent屬性。
3. 在Views\Todo\Components\PriorityList 資料夾下建立Default.cshtml Razor 檢視,新增以下標記:
@model IEnumerable<TodoList.Models.TodoItem> <h3>Priority Items</h3> <ul> @foreach (var todo in Model) { <li>@todo.Title</li> } </ul>
Razor 檢視包含並且顯示了 TodoItems。如果 VC 呼叫方法沒有傳遞檢視的名稱 (如例子中所示),那麼預設情況下則呼叫檢視名稱對於方法。在後續的文章中,將闡述如何傳遞檢視名稱。
在views\todo\index.cshtml 檢視底部新增包含有呼叫PriorityListViewComponent的div:
@model IEnumerable<TodoList.Models.TodoItem> <h3>Priority Items</h3> <ul> @foreach (var todo in Model) { <li>@todo.Title</li> } </ul>
標記 @await Component.InvokeAsync() 表示該語法用於呼叫VC。第一個引數是我們要呼叫的元件名稱。其餘引數引數傳遞給該VC。在這個例子中,我們傳遞“1”作為過濾的優先順序。InvokeAsync 方法可以包含任意數量的引數。
以下圖片顯示了優先順序列表:
@{ 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>
注意: VC通常被新增到 Views\Shared 資料夾下,因為它並不僅僅是controller。
新增InvokeAsync 到優先順序元件
通過以下程式碼更新PriorityListViewComponent類:
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 == " + isDone.ToString(); ViewBag.PriorityMessage = msg; return items; } } }
注意: 這裡移除了用於同步的Invoke 方法,使用更加強大的asynchronous方法替代。
修改 VC 檢視顯示優先順序資訊:
@model IEnumerable<TodoList.Models.TodoItem> <h4>@ViewBag.PriorityMessage</h4> <ul> @foreach (var todo in Model) { <li>@todo.Title</li> } </ul>
最後,更新 views\todo\index.cshtml 檢視檔案:
@* Markup removed for brevity. *@ <div class="col-md-4"> @await Component.InvokeAsync("PriorityList", 2, true) </div> </div>
以下圖片展示了PriorityListViewComponent類和Index檢視的修改效果:
指定檢視名稱
一些複雜的VC在某些情況下也許需要去指定特定的檢視,以下程式碼是通過InvokeAsync 方法指定檢視的方法:
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); }
更改 Views\Todo\Components\PriorityList\Default.cshtml 為 Views\Todo\Components\PriorityList\PVC.cshtml 檢視。更改PVC檢視控制元件來驗證它的使用:
@model IEnumerable<TodoList.Models.TodoItem> <h2> PVC Named Priority Component View</h2> <h4>@ViewBag.PriorityMessage</h4> <ul> @foreach (var todo in Model) { <li>@todo.Title</li> } </ul>
最後,需要更新 Views\Todo\Index.cshtml 檔案:
重新整理頁面檢視更改效果。
在進行開發時,使用 view components 可以更好的檢視頁面效果。如果再借助一些開發工具,還可以大大提高開發效率。ComponentOne Studio for ASP.NET 是ASP.NET平臺上的一整套完備的開發工具包,包含的Web窗體控制元件、MVC scaffolding模板以及HTML5/JavaScript頁面元件,僅通過幾行程式碼就可以在系統中實現豐富的功能。
在MVC6中,更改controller(或其他任何程式碼)時,不需要重新編譯或重新執行應用,僅需要儲存程式碼並且重新整理頁面即可。
以上即為今天希望和大家分享的view components知識,下一篇文章我們將介紹以下兩部分內容:
- 向檢視中新增服務方法。
- 釋出應用到公有云方法。
敬請期待。