第 3 部分:檢視和 ViewModels
作者 :JonGaloway
MVC 音樂市集是一個教學課程應用程式,會介紹並說明如何使用 ASP.NET MVC 和 Visual Studio 進行 Web 開發。
MVC Music Store 是輕量型範例商店實作,可線上銷售音樂相簿,並實作基本網站管理、使用者登入和購物車功能。
本教學課程系列詳細說明建置 ASP.NET MVC 音樂市集範例應用程式所採取的所有步驟。 第 3 部分涵蓋檢視和 ViewModel。
到目前為止,我們剛剛從控制器動作傳回字串。 這是瞭解控制器運作方式的好方法,但不是您想要建置實際 Web 應用程式的方式。 我們將想要更好的方法,將 HTML 產生回流覽網站的瀏覽器 –其中一個,我們可以使用範本檔案更輕鬆地自訂 HTML 內容傳回。 這完全是 Views 的用途。
新增檢視範本
若要使用檢視範本,我們將變更 HomeController Index 方法以傳回 ActionResult,並讓它傳回 View () ,如下所示:
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
return View();
}
}
上述變更表示我們不會傳回字串,而是想要使用 「檢視」來產生結果。
我們現在會將適當的檢視範本新增至專案。 若要這樣做,我們會將文字游標放在 Index 巨集指令方法內,然後按一下滑鼠右鍵並選取 [新增檢視]。 這會顯示 [新增檢視] 對話方塊:
[新增檢視] 對話方塊可讓我們快速且輕鬆地產生 [檢視範本檔案]。 根據預設,[新增檢視] 對話方塊會預先填入要建立的檢視範本名稱,使其符合將使用它的動作方法。 由於我們在 HomeController 的 Index () 巨集指令方法中使用了 [新增檢視] 操作功能表,因此上述的 [新增檢視] 對話方塊預設會預先填入檢視名稱。 我們不需要變更此對話方塊中的任何選項,因此請按一下 [新增] 按鈕。
當我們按一下 [新增] 按鈕時,Visual Web Developer 會在 \Views\Home 目錄中建立新的 Index.cshtml 檢視範本,如果不存在,則會建立資料夾。
「Index.cshtml」 檔案的名稱和資料夾位置很重要,並遵循預設 ASP.NET MVC 命名慣例。 目錄名稱 \Views\Home 符合名為 HomeController 的控制器。 檢視範本名稱 Index 符合將顯示檢視的控制器動作方法。
ASP.NET MVC 可讓我們避免當我們使用此命名慣例傳回檢視時,必須明確指定檢視範本的名稱或位置。 當我們在 HomeController 中撰寫類似下面的程式碼時,預設會轉譯 \Views\Home\Index.cshtml 檢視範本:
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
return View();
}
}
在按一下 [新增檢視] 對話方塊中的 [新增] 按鈕之後,Visual Web 開發人員已建立並開啟 「Index.cshtml」 檢視範本。 Index.cshtml 的內容如下所示。
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
此檢視使用 Razor 語法,比 ASP.NET Web Forms和舊版 ASP.NET MVC 中使用的Web Form檢視引擎更簡潔。 Web Form檢視引擎仍可在 ASP.NET MVC 3 中使用,但許多開發人員發現 Razor 檢視引擎非常適合 ASP.NET MVC 開發。
前三行會使用 ViewBag.Title 設定頁面標題。 我們很快就會更詳細地查看其運作方式,但首先讓我們更新文字標題文字並檢視頁面。 <更新 h2 > 標籤以說「這是首頁」,如下所示。
@{
ViewBag.Title = "Index";
}
<h2>This is the Home Page</h2>
執行應用程式會顯示我們的新文字會顯示在首頁上。
使用一般網站元素的版面配置
大部分的網站都有許多頁面之間共用的內容:流覽、頁尾、標誌影像、樣式表單參考等。Razor 檢視引擎可讓您輕鬆地使用名為 _Layout.cshtml 的頁面來管理,此頁面已在 /Views/Shared 資料夾內自動為您建立。
按兩下此資料夾以檢視如下所示的內容。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>@ViewBag.Title</title>
<link href="@Url.Content("~/Content/Site.css")"
rel="stylesheet" type="text/css" />
<script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")"
type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/modernizr-1.7.min.js")"
type="text/javascript"></script>
</head>
<body>
@RenderBody()
</body>
</html>
來自個別檢視的內容將會由 @RenderBody() 命令顯示,而我們想要出現在 外部的任何一般內容都可以新增至 _Layout.cshtml 標記。 我們想要讓 MVC 音樂市集擁有通用標頭,其中包含網站中所有頁面上 [首頁] 和 [市集] 區域的連結,因此我們會將該標頭直接新增至該 @RenderBody() 語句上方的範本。
<!DOCTYPE html>
<html>
<head>
<title>@ViewBag.Title</title>
<link href="@Url.Content("~/Content/Site.css")"
rel="stylesheet" type="text/css" />
<script src="@Url.Content("~/Scripts/jquery-1.4.4.min.js")"
type="text/javascript"></script>
</head>
<body>
<div id="header">
<h1>
ASP.NET MVC MUSIC STORE</h1>
<ul id="navlist">
<li class="first"><a href="/"
id="current">Home</a></li>
<li><a
href="/Store/">Store</a></li>
</ul>
</div>
@RenderBody()
</body>
</html>
更新 StyleSheet
空的專案範本包含非常簡化的 CSS 檔案,只包含用來顯示驗證訊息的樣式。 我們的設計工具已提供一些額外的 CSS 和影像來定義網站的外觀與風格,因此我們現在會新增這些影像。
更新的 CSS 檔案和影像包含在 MVC-Music-Store提供的 MvcMusicStore-Assets.zip 內容目錄中。 我們會在 Windows 檔案總管中選取這兩者,並將其放入 Visual Web Developer 中解決方案的內容資料夾,如下所示:
系統會要求您確認是否要覆寫現有的 Site.css 檔案。 按一下 [是]。
應用程式的 [內容] 資料夾現在會顯示如下:
現在讓我們執行應用程式,並查看我們的變更在 [首頁] 上的外觀。
- 讓我們檢閱變更的內容:HomeController 的 Index 巨集指令方法找到並顯示 \Views\Home\Index.cshtmlView 範本,即使我們的程式碼稱為 「return View () 」,因為我們的 View 範本遵循標準命名慣例。
- 首頁會顯示在 \Views\Home\Index.cshtml 檢視範本內定義的簡單歡迎訊息。
- 首頁使用我們的 _Layout.cshtml 範本,因此歡迎訊息會包含在標準網站 HTML 版面配置中。
使用模型將資訊傳遞至我們的檢視
只顯示硬式編碼 HTML 的檢視範本不會製作非常有趣的網站。 若要建立動態網站,我們將改為想要將資訊從控制器動作傳遞至檢視範本。
在 Model-View-Controller 模式中,Model 一詞是指代表應用程式中資料的物件。 模型物件通常對應至資料庫中的資料表,但不需要。
會傳回 ActionResult 的控制器動作方法可以將模型物件傳遞至檢視。 這可讓控制器清楚封裝產生回應所需的所有資訊,然後將此資訊傳遞至檢視範本,以用來產生適當的 HTML 回應。 藉由查看其運作方式,這是最簡單的瞭解,因此讓我們開始著手。
首先,我們將建立一些模型類別來代表商店內的內容類型和相簿。 讓我們從建立內容類型類別開始。 以滑鼠右鍵按一下專案內的 [Models] 資料夾,選擇 [新增類別] 選項,並將檔案命名為 「Genre.cs」。
然後將公用字串 Name 屬性新增至已建立的類別:
public class Genre
{
public string Name { get; set; }
}
注意:萬一您想知道,{ get; set; } 標記法是使用 C# 的自動實作屬性功能。 這可提供屬性的優點,而不需要我們宣告備份欄位。
接下來,請遵循相同的步驟,建立名為 Album.cs) 且具有 Title 和 Genre 屬性的 Album 類別 (:
public class Album
{
public string Title { get; set; }
public Genre Genre { get; set; }
}
現在我們可以修改 StoreController,以使用顯示模型動態資訊的檢視。 如果 - 基於示範目的,我們根據要求識別碼命名為相簿,我們可以如以下檢視所示顯示該資訊。
我們將從變更 [市集詳細資料] 動作開始,以顯示單一相簿的資訊。 將 「using」 語句新增至 StoreControllers 類別頂端,以包含 MvcMusicStore.Models 命名空間,因此我們不需要在每次使用相簿類別時輸入 MvcMusicStore.Models.Album。 該類別的 「usings」 區段現在應該會顯示如下。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcMusicStore.Models;
接下來,我們將更新 Details 控制器動作,使其傳回 ActionResult 而非字串,如同使用 HomeController 的 Index 方法所做的一樣。
public ActionResult Details(int id)
現在我們可以修改邏輯,將 Album 物件傳回至檢視。 稍後在本教學課程中,我們將從資料庫擷取資料,但現在我們將使用「虛擬資料」來開始使用。
public ActionResult Details(int id)
{
var album = new Album { Title = "Album " + id };
return View(album);
}
注意:如果您不熟悉 C#,您可能會假設使用 var 表示我們的相簿變數晚期繫結。 不正確 – C# 編譯器會根據我們指派給變數的內容來判斷相簿的類型,並將本機相簿變數編譯為相簿類型,因此我們會取得編譯時期檢查和 Visual Studio 程式碼編輯器支援。
現在,讓我們建立使用相簿來產生 HTML 回應的檢視範本。 在這麼做之前,我們需要建置專案,讓 [新增檢視] 對話方塊知道我們新建立的相簿類別。 您可以選取 [偵錯]⇨[建置 MvcMusicStore] 功能表項目來建置專案, (額外的點數,您可以使用 Ctrl-Shift-B 快捷方式來建置專案) 。
既然我們已設定支援類別,我們即可建置檢視範本。 在 [詳細資料] 方法內按一下滑鼠右鍵,然後選取 [新增檢視...]從操作功能表。
我們將建立新的檢視範本,就像使用 HomeController 之前所做的一樣。 因為我們是從 StoreController 建立它,所以預設會在 \Views\Store\Index.cshtml 檔案中產生。
不同于之前,我們將勾選 [建立強型別] 檢視核取方塊。 然後,我們會在 [檢視資料類別] 下拉式清單中選取 「相簿」類別。 這會導致 [新增檢視] 對話方塊建立 [檢視] 範本,預期將相簿物件傳遞至該物件以使用。
當我們按一下 [新增] 按鈕時,將會建立 \Views\Store\Details.cshtml 檢視範本,其中包含下列程式碼。
@model MvcMusicStore.Models.Album
@{
ViewBag.Title = "Details";
}
<h2>Details</h2>
請注意第一行,這表示這個檢視是強型別的相簿類別。 Razor 檢視引擎瞭解它已傳遞相簿物件,因此我們可以輕鬆地存取模型屬性,甚至可在 Visual Web 開發人員編輯器中享有 IntelliSense 的優點。
<更新 h2 > 標記,使其藉由修改該行以顯示相簿的 Title 屬性,如下所示。
<h2>Album: @Model.Title</h2>
請注意,當您在 關鍵字之後輸入句點時 @Model ,會觸發 IntelliSense,其中顯示 Album 類別支援的屬性和方法。
現在讓我們重新執行我們的專案,並流覽 /Store/Details/5 URL。 我們將會看到相簿的詳細資料,如下所示。
現在,我們將針對市集流覽動作方法進行類似的更新。 更新 方法以傳回 ActionResult,並修改方法邏輯,使其建立新的 Genre 物件,並將其傳回至 View。
public ActionResult Browse(string genre)
{
var genreModel = new Genre { Name = genre };
return View(genreModel);
}
以滑鼠右鍵按一下 [流覽] 方法,然後選取 [新增檢視...]。從操作功能表,然後新增強型別的檢視,將強型別新增至內容類型類別。
更新 / < Views/Store/Browse.cshtml) 中檢視程式碼 (中的 h2 > 元素,以顯示內容類型資訊。
@model MvcMusicStore.Models.Genre
@{
ViewBag.Title = "Browse";
}
<h2>Browsing Genre: @Model.Name</h2>
現在讓我們重新執行專案,並流覽至 /Store/Browse?Genre=Disco URL。 我們將會看到如下所示的 [流覽] 頁面。
最後,讓我們對 市集索引 動作方法進行稍微複雜的更新,並檢視以顯示市集中所有內容類型的清單。 我們將使用內容類型清單作為模型物件,而不只是使用單一內容類型來執行此動作。
public ActionResult Index()
{
var genres = new List<Genre>
{
new Genre { Name = "Disco"},
new Genre { Name = "Jazz"},
new Genre { Name = "Rock"}
};
return View(genres);
}
以滑鼠右鍵按一下 [市集索引] 動作方法,然後選取 [新增檢視],然後選取 [內容類型] 作為 [模型] 類別,然後按 [新增] 按鈕。
首先,我們將變更 @model 宣告,以指出檢視預期有數個內容類型物件,而不只是一個。 將 /Store/Index.cshtml 的第一行變更為讀取,如下所示:
@model IEnumerable<MvcMusicStore.Models.Genre>
這會告訴 Razor 檢視引擎,它會使用可保存數個 Genre 物件的模型物件。 我們會使用 IEnumerable 內容類型,而不是 List < 內容類型 >> ,因為它更泛型,讓我們稍後能夠將模型類型變更為支援 IEnumerable < 介面的任何物件類型。
接下來,我們將迴圈查看模型中的 Genre 物件,如下列已完成的檢視程式碼所示。
@model IEnumerable<MvcMusicStore.Models.Genre>
@{
ViewBag.Title = "Store";
}
<h3>Browse Genres</h3>
<p>
Select from @Model.Count()
genres:</p>
<ul>
@foreach (var genre in Model)
{
<li>@genre.Name</li>
}
</ul>
請注意,當我們輸入此程式碼時,我們具有完整的 IntelliSense 支援,因此當我們輸入 「@Model」。我們會看到類型內容類型 IEnumerable 支援的所有方法和屬性。
在我們的「foreach」迴圈內,Visual Web 開發人員知道每個專案都是內容類型類型,因此我們會看到每個內容類型類型的 IntelliSense。
接下來,Scaffolding 功能會檢查 Genre 物件,並判斷每個物件都有 Name 屬性,因此它會迴圈並寫出它們。它也會產生每個個別專案的 [編輯]、[詳細資料] 和 [刪除] 連結。 我們稍後會在商店經理中利用它,但現在我們想要改為有簡單的清單。
當我們執行應用程式並流覽至 /Store 時,我們會看到 [內容類型] 的計數和清單都會顯示。
在頁面之間新增連結
我們的 /Store URL 列出內容類型目前只會以純文字形式列出內容類型名稱。 讓我們變更此專案,而不是純文字,而是將內容類型名稱連結至適當的 /Store/Browse URL,如此一來,按一下 「Disco」 之類的音樂內容類型就會流覽至 /Store/Browse?genre=Disco URL。 我們可以更新 \Views\Store\Index.cshtml 檢視範本,以使用下列程式碼來輸出這些連結 , (未在 中輸入此內容 - 我們將改善其) :
<ul>
@foreach (var genre in Model)
{
<li><a href="/Store/Browse?genre=@genre.Name">@genre.Name</a></li>
}
</ul>
這可運作,但可能會導致稍後發生問題,因為它依賴硬式編碼字串。 例如,如果我們想要重新命名控制器,我們需要搜尋程式碼,尋找需要更新的連結。
我們可以使用的替代方法是利用 HTML 協助程式方法。 ASP.NET MVC 包含可從我們的檢視範本程式碼取得的 HTML 協助程式方法,以執行各種常見的工作,就像這樣。 Html.ActionLink () 協助程式方法特別有用,而且可讓您輕鬆地建置 HTML <> 連結,並處理令人不想要的詳細資料,例如確定 URL 路徑已正確編碼 URL。
Html.ActionLink () 有數個不同的多載,可讓您指定您連結所需的資訊。 在最簡單的情況下,您只會提供連結文字和 Action 方法,以在用戶端上按一下超連結時移至 。 例如,我們可以使用下列呼叫,連結至 [市集詳細資料] 頁面上的 「/Store/」 Index () 方法,以及連結文字 「Go to the Store Index」:
@Html.ActionLink("Go
to the Store Index", "Index")
注意:在此情況下,我們不需要指定控制器名稱,因為我們只是在轉譯目前檢視的相同控制器內連結到另一個動作。
不過,流覽頁面的連結將需要傳遞參數,因此我們將使用採用三個參數的另一個 Html.ActionLink 方法多載:
-
- 連結文字,其會顯示內容類型名稱
-
- 流覽) (控制器動作名稱
-
- 路由參數值,指定 (內容類型) 的名稱和值 (內容類型名稱)
將所有連結放在一起,以下是我們將如何將這些連結寫入市集索引檢視:
<ul>
@foreach (var genre in Model)
{
<li>@Html.ActionLink(genre.Name,
"Browse", new { genre = genre.Name })</li>
}
</ul>
現在,當我們再次執行專案並存取 /Store/ URL 時,我們會看到內容類型清單。 每個內容類型都是超連結 – 按一下時,會帶我們前往我們的 /Store/Browse?genre=[內容類型] URL。
內容類型清單的 HTML 看起來像這樣:
<ul>
<li><a href="/Store/Browse?genre=Disco">Disco</a>
</li>
<li><a href="/Store/Browse?genre=Jazz">Jazz</a>
</li>
<li><a href="/Store/Browse?genre=Rock">Rock</a>
</li>
</ul>