第 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 檢視範本,如果不存在,則會建立資料夾。

方案總管下拉式功能表的螢幕擷取畫面,其中顯示 M V C 音樂市集中的不同檔案。

「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 中解決方案的內容資料夾,如下所示:

內容目錄和 [音樂市集] 下拉式功能表的並存螢幕擷取畫面,其中顯示內容資料夾中 images 資料夾的檔案路徑。

系統會要求您確認是否要覆寫現有的 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 快捷方式來建置專案) 。

音樂市集檔編輯器的螢幕擷取畫面,其中已選取下拉式功能表中的 [建置] 索引標籤,其中醒目提示 [組建 M V C 音樂市集] 選項。

既然我們已設定支援類別,我們即可建置檢視範本。 在 [詳細資料] 方法內按一下滑鼠右鍵,然後選取 [新增檢視...]從操作功能表。

檢視範本功能表的螢幕擷取畫面,顯示程式碼片段上方,並醒目提示 [新增檢視] 選項。

我們將建立新的檢視範本,就像使用 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。 我們將會看到如下所示的 [流覽] 頁面。

瀏覽器首頁視窗的螢幕擷取畫面,其中顯示標誌影像下方的 [流覽內容類型:disco] 訊息。

最後,讓我們對 市集索引 動作方法進行稍微複雜的更新,並檢視以顯示市集中所有內容類型的清單。 我們將使用內容類型清單作為模型物件,而不只是使用單一內容類型來執行此動作。

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 支援的所有方法和屬性。

H T M L 程式碼片段的螢幕擷取畫面,其中具有功能表列,並選取 [計數 <> ] 命令。

在我們的「foreach」迴圈內,Visual Web 開發人員知道每個專案都是內容類型類型,因此我們會看到每個內容類型類型的 IntelliSense。

[foreach 迴圈] 程式碼的螢幕擷取畫面,其中已選取下拉式功能表視窗,並已選取 [名稱] 選項,且旁邊隨即出現 [字串內容類型點名稱]。

接下來,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 方法多載:

    1. 連結文字,其會顯示內容類型名稱
    1. 流覽) (控制器動作名稱
    1. 路由參數值,指定 (內容類型) 的名稱和值 (內容類型名稱)

將所有連結放在一起,以下是我們將如何將這些連結寫入市集索引檢視:

<ul>
    @foreach (var genre in Model)
    {
        <li>@Html.ActionLink(genre.Name,
"Browse", new { genre = genre.Name })</li>
    }
</ul>

現在,當我們再次執行專案並存取 /Store/ URL 時,我們會看到內容類型清單。 每個內容類型都是超連結 – 按一下時,會帶我們前往我們的 /Store/Browse?genre=[內容類型] URL。

瀏覽器視窗的螢幕擷取畫面,其中顯示 [流覽內容類型] 標題,其中訊息[從 3 個內容類型選取],後面接著三個點符內容類型選取專案。

內容類型清單的 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>