天天看點

ASP.NET MVC3書店--第三節+視圖與視圖模型

     現在我們已經可以從控制器的action方法中傳回字元串了。我們可以藉此來了解控制器是如何來工作的。但在真正的Web應用程式中大多數情況下傳回的都不僅僅是一個字元串。我們更需要的是當使用者輸入URL位址請求時,能夠傳回給浏覽器一串HTML格式的輸出流,我們可以借由模闆檔案來更友善地定制這個HTML格式的輸出流,并将其傳回。在ASP.NET MVC中,将這個模闆檔案稱之為視圖。

3.1    追加一個視圖模闆

    為了要使用視圖模闆,我們修改HomeController控制器中的Index方法,使其傳回一個ActionResult對象,并且将return語句修改為return View(),代碼如下所示。

public class HomeController : Controller

{

    //

    // GET: /Home/

    public ActionResult Index()

    {

        return View();

    }

}
           

      接下來,我們在應用程式中追加一個視圖模闆。在Index這個action方法中點選滑鼠右鍵,然後點選“添加視圖”,如圖3-1所示。 

ASP.NET MVC3書店--第三節+視圖與視圖模型

圖3-1 添加視圖

    點選“添加視圖”後,彈出一個“添加視圖”對話框,如圖3-2所示。

ASP.NET MVC3書店--第三節+視圖與視圖模型

圖3-2 添加視圖對話框

    添加視圖對話框使我們可以快速地、友善地産生視圖模闆檔案。在預設情況下,添加視圖對話框将使用該視圖的action方法的名字作為視圖模闆的名字。這裡,因為我們在HomeController控制器中的Index方法中點選了“添加視圖”子菜單,是以在添加視圖對話框中的視圖模闆名字預設為“Index”。在該對話框中,不做任何修改,直接點選添加按鈕。

    點選添加按鈕之後,Visual Web Developer将會在Views檔案夾下的Home檔案夾中自動為我們建立一個名為Index.cshtml的視圖模闆檔案,如圖3-3所示。

ASP.NET MVC3書店--第三節+視圖與視圖模型

圖3-3 Index.cshtml視圖模闆檔案已被建立

    Index.cshtml檔案的命名與存放位置是非常重要的,而且也遵循了ASP.NET MVC的命名約定。“Views\Home”這個檔案夾與HomeController控制器互相對應。Index這個視圖模闆與控制器中傳回該模闆檔案的Index方法互相對應。

當我們使用了這個預設的命名約定來傳回一個視圖的時候,我們可以不用顯式地指定該視圖模闆檔案的存放位置。在HomeController控制器中書寫如下所示的代碼,浏覽器将自動渲染“Views\Home”這個檔案夾中的Index.cshtml視圖模闆檔案。

public class HomeController : Controller

{

    //

    // GET: /Home/

    public ActionResult Index()

    {

        return View();

    }

}
           

      檢視Index.cshtml檔案,代碼内容如下所示。

@{

    ViewBag.Title = "Index";

}

<h2>Index</h2>

           

      在這段代碼中,使用到了Razor視圖引擎,該視圖引擎使用一種比在Web Forms與在之前版本的ASP.NET MVC中更加精簡的代碼書寫方法。在ASP.NET MVC3中,之前的WebForms仍然能夠繼續使用,但是很多開發者發現Razor視圖引擎更加适合ASP.NET MVC的開發。

    上面這三行代碼中使用ViewBag.Title屬性來設定在浏覽器中進行顯示時的浏覽器視窗标題。我們将很快能夠在浏覽器中檢視這一設定的結果,但這裡首先讓我們更新頁面中的标題文字,将<h2>标簽中的文字修改為“網站首頁”,代碼如下所示。

@{

    ViewBag.Title = "首頁";

}

<h2>網站首頁</h2>
           

      運作應用程式,浏覽器中的顯示結果如圖3-4所示。

ASP.NET MVC3書店--第三節+視圖與視圖模型

圖3-4 浏覽器中的Index視圖

3.2 為公共站點元素使用統一布局

大多數網站中都有一個很多頁面共同使用的公共内容:導覽列,腳注,logo圖檔,樣式表等等。Razor視圖引擎使用一個公共頁面來管理這些公共内容,進而使得公共内容的使用與修改變得更加容易。這個公共頁面被命名為“_Layout.cshtml”,在一開始自動建立應用程式的時候,這個檔案也被建立于“/Views/Shared”檔案夾中,如圖3-5所示。

ASP.NET MVC3書店--第三節+視圖與視圖模型

圖3-5 _Layout.cshtml檔案已被建立

    輕按兩下打開該檔案,檔案中代碼如代碼清單3-1所示。

    代碼清單3-1 _Layout.cshtml檔案中内容

<!DOCTYPE html>

<html>

<head>

    <title>@ViewBag.Title</title>

    <link href="@Url.Content(" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" ~/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>

    @RenderBody()

</body>

</html>
           

        MVC3書店這個Web網站擁有一個每個網頁上都會出現的公共标題與兩個公有連結,一個連結到我們的首頁,另一個連結到書籍種類列舉顯示頁面,是以我們将該檔案中的代碼修改如代碼清單3-2所示。

    代碼清單3-2 添加了公共标題與公共連結的_Layout.cshtml檔案

<!DOCTYPE html>

<html>

<head>

    <title>@ViewBag.Title</title>

    <link href="@Url.Content(" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" ~/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 書店</h1>

        <ul id="navlist">

            <li class="first"><a href="/" target="_blank" rel="external nofollow"  id="current">首頁</a></li>

            <li><a href="/Store/" target="_blank" rel="external nofollow" >挑選書籍</a></li>

        </ul>

    </div>

    @RenderBody()

</body>

</html>
           

3.3 更新樣式表

一個空的項目模闆中也會包括一個非常簡單的CSS樣式表檔案,在該樣式表檔案中隻包括了顯示驗證資訊時所用到的樣式。現在我們想在其中加入網站中所需要用到的其他的一些樣式與圖檔,讓我們來看一下應該如何進行添加。首先我們可以将我們的樣式檔案追加在Content檔案夾下,将所有的圖檔追加在Content檔案夾下的Images檔案夾下,如圖3-6所示。

ASP.NET MVC3書店--第三節+視圖與視圖模型

圖3-6 追加樣式表與圖檔

    現在讓我們來運作我們的應用程式,看一下現在的首頁在浏覽器中的顯示效果,如圖3-7所示。

ASP.NET MVC3書店--第三節+視圖與視圖模型

圖3-7 添加了樣式與圖檔後的首頁

    現在讓我們暫時回顧一下Visual Web Developer能夠進行哪些工作:HomeController控制器的Index這個action方法能夠自動找到并顯示Views檔案夾下的Home檔案夾下的Index.cshtml這個視圖模闆,而我們隻需要在代碼中寫入“return View()”語句,因為我們的視圖模闆的命名與存放位置是遵循ASP.NET MVC3的标準約定的。

首頁中顯示了我們在視圖模闆檔案(Views檔案夾下的Home檔案夾下的Index.cshtml檔案)中所指定的“網站首頁”文字。

首頁中使用了前面所講的_Layout.cshtml這個公共視圖模闆檔案,是以顯示出了在公共視圖模闆檔案中所指定的公共資訊。

3.4    使用一個模型來将資訊傳入我們的視圖 

    如果一個視圖模闆檔案中隻是顯示靜态内容的話,是不可能使網站變得多麼生動有趣的。為了要建立一個動态的Web網站,我們需要将資訊從控制器傳入視圖模闆檔案中。

    在MVC(模型-視圖-控制器)架構中,“模型”用來映射應用程式中所使用到的各種資料。通常情況下,模型對象用來映射資料庫中的資料表,但也可以是其他資料。

    控制器中傳回ActionResult對象的action方法可以将一個模型對象傳入視圖。這意味着控制器可以将生成一個響應流時所需要用到的所有資料進行封裝,然後傳入一個視圖模闆檔案,用以生成HTML格式的響應流。接下來我們用一個action方法為例,來看看控制器如何将資料傳入視圖模闆中。

    首先我們将要建立一些模型類,分别代表書店中的書籍種類資訊與某本書籍的具體資訊。為了要建立一個Genre模型類(書籍種類),滑鼠右擊Models檔案夾,點選“添加類”,如圖3-8所示。

ASP.NET MVC3書店--第三節+視圖與視圖模型

圖3-8 添加模型類

    在彈出的添加類對話框中,将類命名為“Genre.cs”,如圖3-9所示。

ASP.NET MVC3書店--第三節+視圖與視圖模型

圖3-9 将模型類命名為“Genre.cs”

    點選添加按鈕,在打開的類檔案中追加一個public(公有)的string(字元串)類型的Name(種類名稱)屬性,代碼如下所示。

public class Genre

{

    public int ID { get; set; }

    public string Name { get; set; }

}
           

      接下來,用同樣的方法添加一個Book(書籍)類,檔案名為Book.cs,添加一個Title(标題)屬性與一個Genre(書籍種類)屬性,代碼如下所示。

public class Book

{

    public string Title { get; set; }

    public Genre Genre { get; set; }

}

    接下來,讓我們修改StoreController控制器,使其能夠使用視圖,展示模型中的資訊。

    首先,我們修改StoreController控制器中的Details這個action方法,使其能夠顯示單本書籍的資訊。在StoreController控制器類的頭部追加一句using語句來引用MvcBookStore.Models命名空間。這樣我可以避免在每次使用Book類的時候都需要鍵入MvcBookStore.Models.Book。StoreController控制器類的頭部處using語句的代碼如下所示。

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Mvc;

using MvcBookStore.Models;

    接下來,我們修改控制器中Details這個action方法,使其不再傳回一個字元串,而是與HomeController控制器中的Index方法同樣,傳回一個ActionResult對象,代碼如下所示。

public ActionResult Details(int id)

    現在我們修改Details方法内部的代碼,使其向視圖中傳入一個Book對象。在後文中我們将可以從資料庫中首先擷取一個Book(書籍)對象的資料,然後再将該Book對象傳入視圖,但是現在我們先暫時直接在代碼中直接寫入Book對象的資料,并傳入視圖,代碼如下所示。

public ActionResult Details(int id)

{

    var book = new Book { Title = "書籍 " + id };

    return View(book);

}

    注意:如果你對C#不很熟悉的話,你也許會認為使用“var”聲明的話就意味着代碼中的book變量是後期綁定的。事實上并不是如此,C#編譯器使用類型引用的基礎是取決于我們給變量賦的值是什麼類型的,因為book的類型是Book,是以編譯器把book變量編譯為一個本地的Book類型的變量,是以我們仍然可以使用C#中的編譯時檢查和Visual Web Developer中的代碼智能輸入功能。

    現在讓我們建立一個顯示單本書籍資訊的視圖模闆。在這之前我們需要重編譯一下我們的應用程式,以確定在添加視圖對話框中的選擇模型類下拉框中可以找到我們剛加入的Book(書籍)模型類。你可以通過點選“調試”菜單中的“生成 MvcBookStore”菜單項來進行編譯,如圖3-10所示。

ASP.NET MVC3書店--第三節+視圖與視圖模型

圖3-10 編譯應用程式

    現在我們的類已經編譯好了,我們可以追加這個展示單本書籍的視圖模闆了。在Details方法中點選滑鼠右鍵,選擇“添加視圖”。如圖3-11所示。

ASP.NET MVC3書店--第三節+視圖與視圖模型

圖3-11 在Details方法中追加視圖

    我們要追加的視圖與之前在HomeController控制器中追加的視圖稍微有所不同,這一次我們在“添加視圖”對話框中勾選“建立強類型視圖”複選框,在模型類下拉框中選擇“Book(MvcBookStore.Models)”,如圖3-12所示。這樣的話添加出來的視圖模闆會自動認為已經從外面接收到了一個Book對象,并且自動追加視圖中對于該對象進行處理的代碼。

ASP.NET MVC3書店--第三節+視圖與視圖模型

圖3-12 添加展示單本書籍資訊所用視圖

    點選添加按鈕,在我們的Views檔案夾下面的Store檔案夾中會自動添加一個Details.cshtml模闆檔案,打開該檔案,其中已經自動添加如下所示的代碼。

@model MvcBookStore.Models.Book

@{

    ViewBag.Title = "Details";

}

<h2>Details</h2>

    請注意第一行,标示着這個視圖是已經使用我們的Book類經過強類型化處理的。Razor視圖引擎會自動将其判定為傳入了一個Book對象。這樣我們可以很輕松地通路我們的模型類中的各個屬性,同時也可以使用Visual Studio編輯器中的智能代碼輸入功能。

    将<h2>标簽中内容修改為如下所示的代碼,使其可以顯示傳入的Book對象的Title屬性中的内容。

<h2>書籍:@Model.Title</h2>

    請注意當你在@Model後面輸入點符号的時候會觸發智能代碼輸入功能,顯示Book類中的各個屬性。

    現在讓我們重新運作我們的應用程式,并通路“/Store/Details/1”這個URL位址,浏覽器中顯示結果如圖3-13所示。

ASP.NET MVC3書店--第三節+視圖與視圖模型

圖3-13 單本書籍資訊展示畫面

    現在我們對Browse這個action方法做類似修改。首先修改方法使其傳回一個ActionResult對象,然後修改方法内部代碼,建立一個新的Genre(書籍種類)對象,并将其傳入視圖,最後傳回該視圖,代碼如下所示。

public ActionResult Browse(int id)

{

    String[] name=new string[3]{“小說”,”教材”,”科學”};

var genreModel = new Genre {ID=id,Name = name[id-1] };

    return View(genreModel);

}

    在Browse方法中點選滑鼠右鍵,然後點選“添加視圖”菜單,然後追加一個強類型視圖,并且在模型類下拉框中選擇“Genre(MvcBookStore.Models)”,如圖3-14所示。

ASP.NET MVC3書店--第三節+視圖與視圖模型

圖3-14 添加書籍種類展示視圖

    更新視圖模闆(Views檔案夾下Store檔案夾中的Browse.cshtml)中的代碼,使其顯示書籍種類資訊,代碼如下所示。

@model MvcMusicStore.Models.Genre

@{

    ViewBag.Title = "書籍種類";

}

<h2>書籍種類: @Model.Name</h2>

    重新運作我們的應用程式,并通路“/Store/Browse/1”這個URL位址,浏覽器中顯示結果如圖3-15所示。

ASP.NET MVC3書店--第三節+視圖與視圖模型

圖3-15 書籍種類展示畫面

    最後,讓我們對StoreController控制器類中的Index這個action方法做一些稍為複雜的修改,使其可以顯示由書店中所有書籍種類組成的清單。我們通過使用一個由我們的模型中的Genre對象所組成的清單(List)來實作這一功能,代碼如下所示。

public ActionResult Index()

{

    var genres = new List<Genre>

    {

        new Genre { ID=1,Name = "小說"},

        new Genre { ID=2, Name = "教材"},

        new Genre { ID=3,Name = "科學"}

    };

    return View(genres);

 }

    在Index方法中點選滑鼠右鍵,然後點選“添加視圖”菜單,然後追加一個強類型視圖,并且在模型類下拉框中選擇“Genre(MvcBookStore.Models)”,在支架模闆下拉框中選擇“List”,如圖3-16所示。

ASP.NET MVC3書店--第三節+視圖與視圖模型

圖3-16 添加書籍種類清單展示視圖

    點選添加按鈕後打開自動建立的視圖檔案,第一行中代碼辨別着視圖中接收到了一個Genre對象所組成的集合。

@model IEnumerable<MvcMusicStore.Models.Genre>

    這行代碼告訴Razor視圖引擎将要處理一個存放了Genre對象所組成集合的模型(model)對象。這裡我們使用IEnumerable<Genre>,而不是使用List<Genre>,因為前者更加通用,允許我們之後可以将視圖中所使用的模型類型修改為其他任何支援Ienumerable接口的集合。

    接下來,我們書寫如下所示的代碼,對模型中的Genre對象所組成的集合進行一個周遊。

@model IEnumerable<MvcMusicStore.Models.Genre>

@{

    ViewBag.Title = "挑選書籍";

}

<h3>書籍種類展示</h3>

<p>

    本書店共出售如下 @Model.Count() 種書籍:</p>

<ul>

    @foreach (var genre in Model)

    {

        <li>@genre.Name</li>

    }

</ul>

    請注意當書寫代碼時智能代碼輸入功能始終處于觸發狀态,例如當我們輸入“@Mode”之後編輯器自動顯示一個Genre類型的IEnumerable接口所支援的各種方法與屬性,如圖3-17所示。  

ASP.NET MVC3書店--第三節+視圖與視圖模型

圖3-17 編輯器自動顯示一個Genre類型的IEnumerable接口所支援的各種方法與屬性

    在“foreach”循環中,Visual Web Developer能夠自動将每一個項目判定為Genre類型,編輯器自動顯示Genre類型所支援的方法與屬性,如圖3-18所示。  

ASP.NET MVC3書店--第三節+視圖與視圖模型

圖3-18編輯器自動顯示Genre類型所支援的方法與屬性

    請注意,在自動建立Genre類型的強類型化視圖的時候,能夠判别出來該類型有個Name屬性,并在進行周遊的時候将該屬性内容寫出。同時自動生成Edit(編輯)連結,Details(資料詳細資訊)連結與Delete(删除)連結。在後文中我們将會針對編輯、删除與資料詳細資訊展示功能進行詳細介紹,這裡暫且略過。

    重新運作應用程式,并且通路“/Store”URL位址,浏覽器中顯示如圖3-19所示。

ASP.NET MVC3書店--第三節+視圖與視圖模型

圖3-19 書籍種類清單畫面

3.5 追加頁面與頁面之間的連結

    現在我們的“/Store”這個URL位址所顯示的頁面中隻是簡單地以文字的形式列舉出了各種書籍種類的名稱。接下來讓我們把此處的種類名稱修改為可以連結到“/Store/Browse”這個URL位址,這樣的話當使用者點選“小說”這個書籍種類的時候,頁面可以轉至“/Store/Browse/1”這個URL位址。

    更新Views檔案夾下的Store檔案夾中的Index.cshtml視圖中的代碼如下所示。

<ul>

    @foreach (var genre in Model)

    {

        <li><a href="/Store/Browse/@genre.ID" target="_blank" rel="external nofollow" >@genre.Name</a></li>

    }

</ul>

    這段代碼是有效的,但非常具有局限性。例如,如果之後我們想改變控制器的名稱,我們還不得不修改此處的代碼。

    一種更好的書寫方法是借助于一個HTML幫助器方法。在ASP.NET MVC的視圖中,可以使用HTML幫助器方法來實作大量類似于此的共通處理。Html.ActionLink()就是其中一個非常有用的HTML幫助器方法,它使得HTML中的<a>連結的書寫方法變得更加容易,同時可以確定連結中使用的URL路徑是正确的URL位址格式。

    Html.ActionLink()有幾個不同的重載方式,進而允許你在連結中指定任何所需要的資訊。譬如在如下所示的簡單示例中,你可以指定連結文字以及當連結在用戶端被點選時所執行的Action方法。例如,在代碼中,我們可以使用“連結到Store位址的Index方法”連結到StoreController控制器中的Index方法中。

@Html.ActionLink("連結到Store位址的Index方法", "Index")

    請注意,在這種情況下,我們不需要指定控制器的名稱,因為我們隻是連結到了使用目前視圖的控制器的另一個action方法中。

    連結到書籍種類展示頁面的時候還需要提供兩個參數,是以我們使用Html.ActionLink()方法的另一種重載方式,使其使用如下參數:

  1. 使用種類名稱作為連結文字。
  2. 控制器中action方法的名稱(Browse)。
  3. 頁面參數,指定ID屬性的屬性名稱與屬性值。

    最終修改代碼如下所示:

<ul>

    @foreach (var genre in Model)

    {

        <li>@Html.ActionLink(genre.Name,"Browse", new {id=genre.ID})

</li>

    }

</ul>

    現在我們可以重新運作我們的應用程式,通路“/Store”這個URL位址,我們可以看見一個所有書籍種類的清單展示頁面,如圖3-20所示。每一個種類都帶有一個超連結,點選該超連結可以通路“/Store/Browse/[書籍ID]”這個URL位址。

ASP.NET MVC3書店--第三節+視圖與視圖模型

圖3-20 所有書籍種類的清單展示頁面

    檢視這個所有書籍種類的清單展示頁面的html源代碼,代碼如下所示。

<ul>

    <li><a href="/Store/Browse/1" target="_blank" rel="external nofollow" >小說</a></li>

    <li><a href="/Store/Browse/2" target="_blank" rel="external nofollow" >教材</a></li>

    <li><a href="/Store/Browse/3" target="_blank" rel="external nofollow" >科學</a></li>

</ul>