ASP.NET MVC5高級編程 之 視圖


1.1理解視圖約定

當創建一個項目模版時,可以注意到,項目以一種非常具體的方式包含了一個結構化的Views目錄。在每一個控制器的View文件夾中,每一個操作方法都有一個同名的視圖文件與其對應。這就提供了視圖與操作方法關聯的基礎。

1 public ActionResult Index() 2 { 3      return View(); 4 }

視圖選擇邏輯在/Views/ControllerName目錄(這里就是去掉Controller后綴的控制器名)下查找與操作方法同名的視圖。此處選擇的是/Views/Home/Index.cshtml。

與ASP.NET MVC中的大部分方法一樣,這一約定是可以重寫的。想讓Index操作方法渲染一個不同的視圖,可以向其提供一個不同的視圖名稱,代碼如下:

1 public ActionResult Index() 2 { 3      return View("NotIndex");  4 }

對於上面的編碼,操作方法依然在/Views/Home目錄中查找視圖,但選擇的不再是Index.cshtml,而是NotIndex.cshtml。

如果需要制定完全位於不同目錄結構中的視圖,編碼如下:

1 public ActionResult Index() 2 { 3      return View("~/Views/Example/Index.cshtml");  4 }

 

 1.2 強類型視圖

假設需要編寫一個顯示Album實例列表的視圖,一種方法是將專輯添加到ViewBag中,然后在視圖中進行迭代。

 1         public ActionResult List()  2  {  3             var albums = new List<Album>();  4             for (int i = 0; i < 10; i++)  5  {  6                 albums.Add(new Album { Title = "Product" + i });  7  }  8             ViewBag.Albums = albums;  9             return View(); 10         }

然后,再在視圖中迭代顯示,如下代碼:

1 <ul>
2  @foreach (Album a in (ViewBag.Albums as IEnumerable<Album>)) 3 { 4    <li>@a.Tilte</li>
5 } 6 </ul>

 注意在枚舉之前需要將動態的ViewBag.Albums轉換為IEnumerable<Album>類型。為了使代碼整潔,可以使用dynamic關鍵字,但是當訪問每個Album對象的屬性時,就不能再使用智能感知功能。

1 <ul> 2 @foreach (dynamic p in ViewBag.Albums) 3 { 4 <li>@p.Tilte</li> 5 } 6 </ul>

強類型視圖既能獲得dynamic的簡潔語法,又能獲得強類型和編譯時檢查的好處(比如正確的輸入屬性和方法名稱)。強類型視圖允許設置視圖的模型類型。因此可以從控制器向視圖傳遞一個在兩端都是強類型的模型對象,從而獲得智能感知、編譯器檢查等好處。

在Controller方法中,可以通過向重載的View方法中傳遞模型實例來指定模型,代碼如下:

1     public ActionResult List() 2  { 3         var Musics = new List<MusicModels>(); 4         for (int i = 0; i < 10; i++) 5  { 6             Musics.Add(new MusicModels { MusicName = "MusicName" + i.ToString() }); 7  } 8         return View(Musics); 9     }

下一步是告知視圖哪種類型的模型正在使用@model聲明。但要注意這里需要輸入模型類型的完全限定類型名(名稱空間和類型名稱),如下所示

1 @model IEnumerable<MvcMusicStore.Models.MusicModels>
2 <ul>
3  @foreach(MvcMusicStore.Models.MusicModels music in Model) 4     <li>@music.SingerName</li>
5 </ul>

如果不想輸入模型類型的完全限定類型名,可使用@using關鍵字,如下所示

1  @using MvcMusicStore.Models 2  @model IEnumerable<MusicModels>
3  <ul>
4  @foreach(MusicModels music in Model) 5      <li>@music.SingerName</li>
6  </ul>

對於在視圖中經常使用的名稱空間,好的方法是在Views目錄下的web.config文件中聲明:

<add namespace="MvcMusicStore.Models">

 

1.3 理解ViewBag、ViewData和ViewDataDictionary

之前介紹了使用ViewBag從控制器向視圖傳遞信息,然后介紹了傳遞強類型模型。現實中,這些都是通過ViewDataDictionary傳遞的。

從技術的角度看,數據從控制器傳送到視圖是通過一個名為ViewData的ViewDataDictionary(這是一個特殊的字典類)。我們可以使用標准的字典語法設置或讀取其中的值:

ViewData["CurrentTime"] = DateTime.Now;

盡管這種語法現在也能用,但是MVC3提供了更簡單的語法,可以利用C#4的dynamic關鍵字。ViewBag是ViewData的動態封裝器。這樣我們就可以按照下面的方式來設置值:

ViewBag.CurrentTime = DateTime.Now;

 ViewBag.CurrentTime和ViewData["CurrentTime"] 起到了等同的作用。

一般來說,大部分代碼使用ViewBag,而不是ViewData,這兩種語法並不存在技術上的差異,僅僅是因為ViewBag相對於字典語法而言看上去好看。

注意,ViewBag和ViewData的差異:

  • 只有當要訪問的關鍵字是一個有效的C#標識符時,ViewBag才起作用。例如,如果在ViewData["Key With Spaces"]中存放一個值,那么就不用使用ViewBag訪問,因為無法通過編譯。
  • 動態值不能作為一個參數傳遞給擴展方法,因為C#編譯器為了選擇正確的擴展方法,在編譯時必須知道每一個參數的真正類型。

 

2.視圖模型

在操作方法上右擊 --> “添加視圖” 

彈出添加視圖頁:

  • View name:當從一個操作方法的上下文中打開這個對話框時,視圖的名稱默認被填充為操作方法的名稱。視圖的名稱是必須有的。
  • Template:一旦選擇一個模型類型,就可以選擇一個基架模版。這些模版利用Visual Studio模版系統來生成基於選擇模型類型的視圖。
  • 引用腳本庫:這個選項用來指示要創建的視圖是否應該包含指向JavaScript庫(如果對視圖有意義的話)的引用。默認情況下,_Layout.cshtml文件既不引用jQuery Validation庫,也不引用Unobtrusive jQuery Validation庫,只引用主jQuery庫。

      當創建一個包含數據條目表單的視圖(如Edit視圖或者Create視圖)時,選擇這個選項會添加對jqueryval捆綁的腳本引用。如果要實現客戶端驗證,那么這些庫就是必須的。除這種情況外,完全可以忽略這個復選框。

  • 創建一個分部視圖:選擇這個意味着要創建的視圖不是一個完整的視圖,因此,Layout選項是不可選用的。生成的部分視圖除了在其頂部沒有<html>標簽和<head>標簽外,很像一個常規的視圖。
  • 使用布局頁:這個選項決定了要創建的視圖是否引用布局,還是成為一個完全獨立的視圖。如果選擇使用默認的布局,就沒必要指定一個布局了,因為在_ViewStart.cshtml文件中已經指定了布局。這個選項是用來重寫默認布局文件的。

 

2.2 Razor視圖引擎

ASP.NET MVC中提供了兩種不同的視圖引擎:較新的Razor視圖引擎和較早的WebForms視圖引擎。

Razor中的核心轉換字符是(@),這個單一字符用作標記-代碼的轉換字符,有時也反過來用作代碼-標記的轉換字符。

這里一共有兩種基本類型的轉換:代碼表達式和代碼快。

<h1>Listing @items.Length items.</h1>

表達式@items.Length是作為隱式表達式來求解的,然后輸出表達式的值3。這里不需要指出代碼表達式的結束位置。

但是Razor自動從代碼轉回標記的能力,也帶來了二義性的問題:

1 @{ 2  string rootNamespace = "MyApp"; 3 } 4 <span>@rootNamespace.Models</span>

這個示例想要的輸出結果是:  <span>MyApp.Models</span>  ,然而實際會出現錯誤,提示string沒有Models屬性,此時需要通過圓括號解決:

1 @{ 2 string rootNamespace = "MyApp"; 3 } 4 <span>@(rootNamespace).Models</span>

這樣可以告訴Razor,.Models是字面量文本,而不是代碼表達式的一部分。

 

對於電子郵件地址時的情況,Razor可以辨別出郵件的模式,進而不處理這種形式的表達式:

<span>support@megacorp.com</span>

但是如果確實想將這種形式的字符串作為一個表達式,也需要合理用圓括號:

對於

<li>Item_@item.Length</li>

期望的輸出結果是<li>Item_3</li>,但是Razor會將其按照字符串進行打印。

處理的方法是:

<li>Item_@(item.Length)</li>

有時也需要使用@符號來進行轉義:

1 <p>
2  You should follow 3  @@aspnet 4 </p>

 

3.Razor語法示例

常見用途下的Razor語法;

  • 隱式代碼表達式

代碼表達式將被計算並將值寫入到響應中,這就是視圖中顯示值的一般原理。

<span>@model.Message</span>
  • 顯示代碼表達式

代碼表達式的值將被計算並寫入到響應中,這就是在視圖中顯示值的一般原理

<span>1 + 2 = @(1 +2 )</span>
  • 無編碼代碼表達式

有些情況下,需要顯式的渲染一些不應該采用HTML編碼的值,這時可以采用Html.Raw方法來保證該值不被編碼

<span>@Html.Raw(model.Message)</span>
  • 代碼塊

不像代碼表達式先求的表達式的值,然后再輸出到響應,代碼塊是簡單地執行代碼部分

1 @{ 2    int x = 123; 3    string y = "because."
4 }
  • 文本和標記相結合

這個例子顯示了在Razor中混用文本和標記的概念,具體如下:

1 @foreach (var item in items) 2 { 3    <span>Item @item.Name.</span>
4 }
  • 混合代碼和純文本

Razor查找標簽的開始位置以確定何時將代碼轉換為標記。然而,有時可能想在一個代碼塊之后立即輸出純文本。例如,在下面的這個例子中就是展示如何在一個條件語句塊中顯示純文本

1 @if (showMessage) 2 { 3    <text>this is plain text</text>
4 }

或者

1 @if (showMessage) 2 { 3  @:this is plain text. 4 }

第一種使用<text>標簽,這樣只是把標簽內容寫入到響應中,而標簽本身則不寫入。第二種方式使用一種特殊的語法,實現代碼到純文本的轉換,但是這種方法每次只能作用於一行文本。

  • 轉義代碼分隔符

可使用“@@”來編碼“@”以達到顯示“@”的目的。此外,時鍾都可以選擇使用HTML編碼來實現。

Razor:

the asp.net twitter handle is &#64;aspnet

或者

the asp.net twitter handle is @@aspnet
  • 代碼注釋
1 @* 2 代碼塊 3 *@

 

4.布局

Razor的布局有助於使應用程序的多個視圖保持一致的外觀。可以使用布局為網站定義公共模版(或只是其中的一部分)。公公模版包含一個或多個占位符,應用程序中的其他視圖為它們提供內容。從某些角度看,布局很像視圖的抽象基類。如下則是一個簡單的布局:

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <title>@ViewBag.Title</title>
 5     </head>
 6     <body>
 7         <h1>@ViewBag.Title</h1>
 8         <div id="main-content">@RenderBody()</div>
 9         <footer>@RenderSection("Footer")</footer>
10     </body>
11 </html>

對應視圖的代碼如下:

 1 @{ 2 Layout = "~Views/Shared/SiteLayout.cshtml"; 3 ViewBag.Title = "The Index"; 4 } 5 6 <p>this is the main content!</p> 7 8 @section Footer{ 9 this is the <strong>footer</strong>. 10 }

@section語法為布局中定義的一個節指定了內容。

默認情況下,視圖必須為布局中定義的每一個節提供內容。如果向當前的布局中添加一個新節時,會使得引用該布局的每一個視圖都不能正常運行。

但是,RenderSection方法有一個重載版本,允許指定不需要的節。可以給required參數傳遞一個false值來標記Footer節是可選的。

<footer>@RenderSection("Footer", required: false)</footer>

有時也在視圖中定義一些默認內容

 1 <footer>
 2  @if (IsSectionDefined("Footer"))  3  {  4  RenderSection("Footer");  5  }  6  else  7  {  8         <span>this is the default footer</span>
 9  } 10 </footer>

 

5.ViewStart

在創建一個默認的ASP.NET MVC項目后,會在Views目錄下自動添加一個_ViewStart.cshtml文件,它指定了一個默認布局

1 @{ 2  Layout = "~/Views/Shared/_Layout.cshtml" 3 }

如果多個視圖都使用都使用同一個布局,就會產生冗余。_ViewStart.cshtml中的代碼先於任何視圖運行,所以一個視圖可以重寫Layout屬性的默認值,從而重新選擇了一個不同的布局。如果一組視圖擁有共同的設置,那么_ViewStart.cshtml中的代碼可以用來對共同的視圖進行統一配置。如果有視圖需要覆蓋統一的設置,只需要修改對應的屬性值即可。

 

6.指定部分視圖

 除了返回視圖之外,操作方法也可以通過PartialView方法以PartialViewResult的形式返回部分視圖:

1 public class HomeController : HomeController 2 { 3     public ActionResult Message() 4  { 5         ViewBag.Message = "this is a partial view."; 6         return PartialView(); 7  } 8 }

這種情形下,渲染的是視圖Message.cshtml,但是如果布局是由_ViewStart.cshtml頁面指定(而不是直接在視圖中)的,將無法渲染布局。

除了不能指定布局之外,部分視圖看起來和正常視圖沒有分別:

<h2>@ViewBag.Message</h2>

在使用Ajax技術進行更新時,部分視圖是很有用的。示例使用jQuery將一個部分視圖的內容加載到一個使用了Ajax調用的當前視圖中:

1 <div id="result"></div>
2 @section scripts{ 3 <script type="text/javascript">
4 $(function(){ 5 $('#result').load('/home/message'); 6 }); 7 </script>
8 }

代碼使用jQuery的load方法向Message操作方法發出一個Ajax請求,而后使用請求的結果更新id屬性值為result的DIV元素。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM