前言
有網友說不要浪費時間了趕緊干點正事,也有人覺得還不錯;我個人覺得看懂是一回事,但是能夠寫出來分享是另一回事,這樣記憶深刻有助於加深自己的理解,而且可以幫助有些和我一樣的初學者,遇到的問題,怎么解決等等.
好了,下面開始正題.上周做完第二篇控制器之后,接下來就是第三篇 視圖和模型了,源文章鏈接:http://www.asp.net/mvc/tutorials/mvc-music-store/mvc-music-store-part-3
概述
本章通過簡單的幾個示例,介紹視圖的使用方法以及控制器和視圖之間的數據傳遞方法,簡單而且直觀,並且簡單介紹了生成頁面鏈接的方法.
內容
先來回顧一下:我們之前已經使用控制器返回String 類型的字符,這很好的讓我們了解了控制器的工作原理,但是這不是真正的web應用程序.
我們想要一個更簡單的方式返回HTML內容到瀏覽器--模版文件可以輕松地自定義HTML內容並發回瀏覽器,這就是視圖.
1.添加第一個視圖:
要應用視圖,首先要改變HomeController 控制器的 Index方法的返回值為ActionResult,並且我們讓他返回一個View();代碼如下:
3 // GET: /Home/
4
5 public ActionResult Index()
6 {
7 return View();
8 }
上面的代碼表示,我們想使用視圖得到一個結果返回.
我們現在添加一個視圖 到我們的項目里面,光標定位到Index()方法,右鍵單擊選擇添加視圖:
添加視圖對話框允許我們快速方便地生成視圖文件,默認情況下,添加視圖對話框已經為我們光標定位的控制器方法添加好了名稱,我們不需要修改什么,直接點擊確定,就會添加一個試圖文件到工程目錄:Views/Home/Index.cshtml.
視圖文件的名字和目錄非常重要,使用Mvc默認的命名規則,目錄/View/Home 對應HomeController,文件Index.cshtml對應控制器方法:Index(). 使用這種命名規則,我們不用在Index()方法中顯示指定視圖文件,而是直接 return View().就像上面的HomeController.Index(),它將會自動引用View/Home/Index.cshtml.
添加完視圖之后,默認會打開該視圖文件,默認代碼如下:
3 }
4
5 < h2 >Index </ h2 >
該視圖文件使用 Razor 語法 ,這比Asp.net Web Forms 中的 Web Forms視圖引擎和上一版本的Asp.net mvc 更簡潔.當然 WebForms視圖引擎在Asp.net 3.0中仍然可用,但是很多開發者覺得Razor更加適用於Asp.net Mvc 開發.
前三行代碼設置頁面標題ViewBag.Title.我們等一下將看看它是怎么工作的,現在我們改一下頁面的代碼:
3 }
4
5 < h2 >This is the Home Page </ h2 >
接下來運行程序看一下主頁,會看到我們已經更新的文本:
現在,我們已經為HomeController.Index添加了視圖Index.cshtml,並且運行了出來。下面我們即將看一下Mvc給我們提供的統一網站部局文件.
2.使用統一布局文件
很多網站的網頁有一些全站公用的東西:導航,頁腳,LOGO,CSS文件等.Razor 讓我們很輕松地管理這些東西,使用_Layout.cshtml,工程已經為我們建立此文件,位於:/Views/Shared/_Layout.cshtml.
我們看一下布局文件:
3 < head >
4 < meta charset ="utf-8" />
5 < title >@ViewBag.Title </ title >
6 < link href ="@Url.Content(" ~/Content/Site.css")" rel ="stylesheet" type ="text/css" />
7 < script src ="@Url.Content(" ~/Scripts/jquery-1.7.1.min.js")" type ="text/javascript" ></ script >
8 < script src ="@Url.Content(" ~/Scripts/modernizr-2.5.3.js")" type ="text/javascript" ></ script >
9 </ head >
10
11 < body >
12 @RenderBody()
13 </ body >
14 </ html >
很簡單,僅包含一些CSS和常規腳本.我們的視圖文件將會通過 @RenderBody()命令來展示,其他的公共內容都可以在這里添加,我們想讓我們的MuvMusicStore用一個公共的頁眉,上面包含首頁鏈接和商店鏈接,所以,我們在@RenderBody()命令上面添加一些代碼(黃色高亮部分),個人覺得這里和母版差不多.
添加完之后,先不要運行
3 < head >
4 < meta charset ="utf-8" />
5 < title >@ViewBag.Title </ title >
6 < link href ="@Url.Content(" ~/Content/Site.css")" rel ="stylesheet" type ="text/css" />
7 < script src ="@Url.Content(" ~/Scripts/jquery-1.7.1.min.js")" type ="text/javascript" ></ script >
8 < script src ="@Url.Content(" ~/Scripts/modernizr-2.5.3.js")" type ="text/javascript" ></ script >
9 </ head >
10
11 < body >
12 < div id ="header" >
13 < h1 > ASP.NET MVC MUSIC STORE </ h1 >
14 < ul id ="navlist" >
15 < li class ="first" >< a href ="/"
16 id ="current" > Home </ a ></ li >
17 < li >< a
18 href ="/Store/" > Store </ a ></ li >
19 </ ul >
20 </ div >
21 @RenderBody()
22 </ body >
23 </ html >
空項目模版進包含一些基本的css用於顯示驗證消息,本項目設計師添加了一些常用的Css和一些圖片來控制我們的應用程序的外觀,我們需要把這些文件同時添加進項目里(可以去這里下載)
下載完成解壓之后,打開相關文件包,選擇我們需要的文件添加到項目里:
現在,我們重新生成並刷新首頁:
是不是很熟悉:這就是母版.
簡單回顧一下:
- HomeCongroller.Index引用並展示/Views/Home/Index.cshtml ,盡管我們並沒有顯示指定視圖文件地址而只是使用return View();但是因為我們使用Mvc默認命名規則,所以,這樣並不會導致找不到文件.
- 首頁通過視圖文件展示一個簡單的歡迎信息.
- 使用統一布局文件,讓歡迎信息顯示於全局統一風格的頁面中。
3.使用模型傳遞數據到視圖
只有html代碼的靜態頁面不能滿足我們的應用程序要求,我們需要的是一個能夠和用戶溝通的動態網站,我們需要把數據從控制器傳遞到視圖文件.
在Model-view-controller模式里,Model表示 應用程序中的數據.Model一般對應數據庫中的表,但這不是必須的.
返回一個ActionResult的控制器可以傳遞一個Model到視圖,控制器可以打包所有需要的數據,生成輸出並傳遞到目標視圖文件用來得到Html輸出給瀏覽器,這很簡單,讓我們看看怎么做.
首先我們需要建立一些Model類:Genres(流派),Albums(相冊).右擊/Models/文件夾,選擇添加/類,命名為:Genre.cs,確定之后編輯器會打開Genre.cs文件,我們添加公共屬性Name
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Web;
6
7 namespace MvcMusicStore.Models
8 {
9 public class Genre
10 {
11 public string Name { get; set; }
12 }
13 }
相同步驟創建Album.cs,有一個Title屬性和 Genre屬性:
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Web;
6
7 namespace MvcMusicStore.Models
8 {
9 public class Album
10 {
11 public string Title { get; set; }
12 public Genre Genre { get; set; }
13 }
14 }
現在,我們可以修改StoreController 使用視圖從模型顯示動態信息,我們給Albums一個和Request ID相同的名字(演示起見).
首先:打開StoreController.cs,修改Details 方法,讓它顯示一個相冊的信息,引入MuvMusicStore.Models命名空間以便於使用相關模型類,修改Detail的返回值類型:string to ActionResult,修改方法邏輯:返回一個Album對象給View(稍后我們會講如何從數據庫檢索數據), 但是現在我們將使用“模擬數據”.
給Details添加視圖文件,不過這個步驟要復雜一點點,在添加視圖對話框里我們要勾選“創建強類型視圖” 然后在下面選擇 Album (MvcMusicStore.Models),如果下拉框里面沒有選項,請重新生成項目后重試,支持模版就用Empty ,勾選 引用腳本庫,點擊確定我們會看到生成的視圖文件如下:
3
4 @{
5 ViewBag.Title = " Details ";
6 }
7
8 <h2>Details</h2>
比我們剛才添加的HomeController.Index的視圖多了第一行:它表明這個視圖強制關聯到 Album class,Razor引擎會識別傳進來的Album對象,所以我們可以在視圖編輯器中輕松訪問 模型屬性,並且寫代碼時候能夠自動感應.
更新<h2>標簽內容:
3
4 @{
5 ViewBag.Title = " Details ";
6 }
7
8 <h2>Album: @Model.Title</h2>
9
當你輸入 @Model 之后,智能感知便會出現所有的成員.
現在我們重新生成之后訪問 /Store/Details/5 :
現在我們給Browse方法一個相應的修改:
更新StroeController.Browse方法:
3 {
4 var genreModel = new Genre { Name = genre };
5 return View(genreModel);
6 }
給Browse 添加視圖,強類型關聯到Genre
更新Browse.cshtml代碼:
3 @{
4 ViewBag.Title = " Browse ";
5 }
6 <h2>Browsing Genre: @Model.Name</h2>
重新生成項目並訪問 /Store/Browse?Genre=Disco:
最后,我們給StoreController.Index一個稍微復雜的邏輯和視圖來展示一個流派列表,我們使用一個Genres列表,而不是單個對象:
StoreController.Index代碼:
4 public ActionResult Index()
5 {
6 var genres = new List<Genre>
7 {
8 new Genre { Name = " Disco "},
9 new Genre { Name = " Jazz "},
10 new Genre { Name = " Rock "}
11 };
12 return View(genres);
13 }
給Index添加視圖強類型管理到Genre,打開視圖文件Models/Store/Index.cshtml,把第一行的接收參數生命更新:
3 @*@model MvcMusicStore.Models.Genre *@
4 @model IEnumerable<MvcMusicStore.Models.Genre>
@**@表示注釋代碼
第四行代碼表示我們將接受多個Genre對象;
我們使用 IEnumerable<Genre>而不是 List<Genre>,是因為IEnumerable更為通用,我們可以傳遞任意實現IEnumerable接口的參數類型.
下面我們將遍歷Genre對象:
3 @model IEnumerable<MvcMusicStore.Models.Genre>
4 @{
5 ViewBag.Title = " Store ";
6 }
7 <h3>Browse Genres</h3>
8 <p>
9 Select from @Model.Count()
10 genres:
11 </p>
12 <ul>
13 @foreach ( var genre in Model)
14 {
15 <li>@genre.Name</li>
16 }
17 </ul>
任然有非常強悍的智能感知:比如輸入@Model會出來所有支持的成員;
循環內部,每個 var生命的genre 也可以智能感知所有的成員;
現在我們已經可以循環傳入對象列表,並輸出對象總數以及每個對象的信息,以后我們會生成編輯、查看詳細信息和刪除操作到每一項,現在我們先來看看簡單列表:
重新生成項目,訪問 /Store:
4.添加站內鏈接
剛才的 /Store頁面展示了一組Genre對象的Name屬性作為普通文本,我們給他們加上鏈接,通過點擊訪問相關的詳細信息/Store/Browse,當我們點擊 "Disco",能夠跳轉到/Store/Browse?genre=Disco,我們更新/Views/Store/Index.cshtml的代碼:
3 @foreach (var genre in Model)
4 {
5 < li >< a href ="/Store/Browse?genre=@genre.Name" >@genre.Name </ a ></ li >
6 }
7 </ ul >
這樣可以實現,但是不是很好的方式,比如我們要更新Browse為BrowseDetail,那就需要檢索整個項目來查找需要更新的地方.
另一個實現方式就是利用 HTML Helper 方法.Asp.net Mvc包含HTML Helper方法,在View編輯器中,我們可以使用它來完成相關的任務. Html.ActionLink()是一個特別有用的方法,使用它創建鏈接,維護路徑,還是確保URL編碼都比較簡單,
Html.ActionLink()有幾個重載允許我們傳入需要的各種參數, 在示例中我們僅需要提供鏈接文本和目標Action,比如我們可以在Store Details 頁面點擊"Go to Store Index" 連接到"/Store"頁面,用法如下:
鏈接到Browse頁面需要一個參數,所以我們需要另外一個重載,它將支持三個參數:
- 鏈接文本
- 控制器名稱
- 參數 包括參數名和參數值
下面看一下代碼:
3 @model IEnumerable<MvcMusicStore.Models.Genre>
4 @{
5 ViewBag.Title = " Store ";
6 }
7 <h3>Browse Genres</h3>
8 <p>
9 Select from @Model.Count()
10 genres:
11 </p>
12 <ul>
13 @foreach ( var genre in Model)
14 {
15 <li> @Html.ActionLink(genre.Name,
16 " Browse " , new { genre = genre.Name })</li>
17 }
18 </ul>
重新生成項目,訪問 /Store/ :
查看源代碼:
3 < li >< a href ="/store/Browse?genre=Disco" >Disco </ a ></ li >
4 < li >< a href ="/store/Browse?genre=Jazz" >Jazz </ a ></ li >
5 < li >< a href ="/store/Browse?genre=Rock" >Rock </ a ></ li >
6 </ ul >
可以發現,解析出來的html代碼和預期的相同.
個人感悟
通過這章,可以發現,在mvc中,業務邏輯和表示層分離的程度非常高,幾乎可以同時開始編碼,而不用擔心其他問題.我們將在下一章介紹模型和數據訪問.