視圖(View) – ASP.NET MVC 4 系列

       精心編寫的整潔代碼是開發一個可維護 Web 應用程序的基礎。但用戶在瀏覽器中訪問時,這些工做他們是看不見的。用戶對應用程序的第一印象,以及與應用程序的整個交互過程都是從視圖開始的。html

       按照約定,每一個控制器在 Views 目錄下都有一個對應的文件夾,其名稱與控制器同樣,只是沒有 Controller 後綴名。在每個控制器的 View 文件夾中,每個操做方法都有一個同名的視圖文件與其相對應,這就提供了視圖與操做方法關聯的基礎瀏覽器

       操做方法經過 View 方法返回 ViewResult 對象,如默認模板中的 Home 代碼以下:app

public ActionResult Index()
{
    ViewBag.Message = "I like cake!";
    return View();
}

       當不指定視圖名稱時,操做方法返回的 ViewResult 對象將按照約定來肯定視圖。它會在目錄 /Views/ControllerName(不帶 Controller 後綴) 下查找與 action 名稱相同的視圖,這種狀況下默認選擇的視圖即是 /Views/Home/Index.cshtml。佈局

       這一約定是能夠重寫的,若是想讓 Index 操做方法渲染一個不一樣的視圖,能夠向其提供一個不一樣的視圖名稱:(仍會在 Home 文件夾中尋找指定視圖)spa

return View("NotIndex");3d

       另外,在一些應用中,還可能須要指定徹底位於不一樣目錄結構中的視圖,針對這種狀況,可使用帶有「~」符號的語法提供視圖的完整路徑:code

return View("~/Views/Example/Index.cshtml");htm

       注意,爲了在查找視圖時避開視圖引擎的內部查找機制,使用這種語法時,必須提供視圖的文件擴展名對象

ViewData 和 ViewBag

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

ViewData["CurrentTime"] = DateTime.Now;

       但如今有了更簡單的語法,它利用了 C# 4.0 的 dynamic 字段。ViewBag 是 ViewData 的動態封裝器,這樣咱們就可使用下面的語法:

ViewBag.CurrentTime = DateTime.Now;

       所以,ViewBag.CurrentTime 等同於 ViewData["CurrentTime"] 。二者之間並不存在真正的技術差別,ViewBag 只是更受歡迎的語法而已

       但兩者之間的一些關鍵差別仍是須要知道的:

  1. 當要訪問的關鍵字是一個有效的 C# 標識符,ViewBag 才起做用。若是在 ViewData["Key With Spaces"] 中存放一個值,ViewBag 根本沒法使用,由於根本不能經過編譯!
  2. 動態值不能做爲一個參數傳遞給擴展方法,C# 編譯器爲了選擇正確的擴展方法,在編譯時必需知道每個參數的真正類型。若是其中任何一個參數是動態的,那麼就不會經過編譯,例如,@Html.TextBox("name",ViewBag.Name); 要使這行代碼經過編譯,有 2 種辦法,第一是使用 ViewData["Name"],第二是轉換爲具體類型 (string)ViewBag.Name。

強類型視圖

       假設須要編寫一個顯示 Album 實例列表的視圖,一種簡單方法就是經過 ViewBag 屬性把那些 Album 實例添加到視圖數據字典中,而後再視圖中迭代它們。

public ActionResult List()
{
    var albums = new List<Album>();
    for (int i = 0; i < 10; i++)
    {
        albums.Add(new Album(Title = "Product " + i));
    }
    ViewBag.Albums = albums;
    return View();
}
<ul>
    @foreach (Album A in ViewBag.Albums as IEnumerable<Album>)
    {
 <li>@a.Title</li>
    }
</ul>

       注意,枚舉以前須要將動態的 ViewBag.Albums 轉換爲 IEnumerable<Album>類型。

       爲了使視圖代碼乾淨整潔,這裏也可使用 dynamic 關鍵字,可是當訪問每一個 Album 對象的屬性時,就失去了智能感知功能。

<ul>
    @foreach (dynamic p in ViewBag.Albums)
    {
 <li>@p.Title</li>
    }
</ul>

       若是既能得到 dynamic 下的簡潔語法,又能得到強類型和編譯時檢查的好處(好比正確的輸入屬性和方法名稱)就完美了,可喜的是,強類型的視圖能夠作到這一點。

       另外,ViewData 是 ViewDataDictionary 類型的,而不只是一個通用的  Dictionary。之因此這樣,是由於它有一個額外的 Model 屬性,能夠用來在視圖中獲取指定的模型對象,ViewData 中只能包含一個模型對象

public ActionResult List()
{
    var albums = new List<Album>();
    for (int i = 0; i < 10; i++)
    {
        albums.Add(new Album(Title = "Product " + i));
    }
    return View(albums);
}

       後臺首先會把傳給 View 方法的值賦給 ViewData.Model 屬性,而後告知視圖哪一種類型的模型正在使用 @model 聲明。注意,這裏須要輸入模型類型的徹底限定類型名:

@model IEnumerable<MvcMusicStore.Models.Album>
<ul>
    @foreach (Album p in Model)
    {
 <li>@p.Title</li>
    }
</ul>

       若是不想輸入模型的徹底限定類型名,可以使用 @using 關鍵字聲明:

@using MvcMusicStore.Models
@model IEnumerable<Album>
<ul>
    @foreach (Album p in Model)
    {
 <li>@p.Title</li>
    }
</ul>

視圖模型

       視圖一般要顯示各類沒有直接映射到域模型的數據。例如,有時須要顯示商品附帶的其餘信息,好比當前登陸系統的用戶名、該用戶是否有權限編輯商品等。把與視圖主模型無關的數據存放在 ViewBag 屬性中,能夠很容易實現這些數據在視圖中的顯示,也是一個靈活的方法。

       但這並不適用於每一個人。若是要嚴格控制流入視圖的數據,就必須使全部數據都是強類型數據,以便視圖編寫人員可以利用智能感知功能。可能採用的方式是編寫自定義的視圖模型類,這個模型僅限於向視圖提供信息的模型。(這裏說的視圖模型不是 Model View ViewModel,MVVM 模式中的視圖模型概念)

       例如,若是須要一個購物車彙總頁面,用來顯示商品列表、商品總金額、顯示給用戶的消息,就能夠建立 ShoppingCartSummaryViewModel 類,以下所示:

public class ShoppingCartSummaryViewModel 
{
    public IEnumerable<Product> Products { get; set; }
    public decimal CartTotal { get; set; }
    public string Message { get; set; }
}

       而後可使用 @model 指令,將這個模型強制性的輸入到一個視圖:

@model ShoppingCartSummaryViewModel

       這就在不須要改變 Model 類的狀況下帶來了強類型視圖的益處,其中包括類型檢查、智能感知以及免於轉換無類型的 ViewDataDictionary 對象。

添加視圖

       在 HomeController 中添加一個 Edit 操做方法,右擊操做方法添加一個視圖:

public ActionResult Edit()
{
    return View();
}

image

       建立爲分部視圖時,意味着要建立的視圖不是一個完整的視圖,所以,Layout 選項是不可用的。

       使用佈局頁,對於 Razor 視圖引擎來講,若是使用默認佈局,就不必指定了,由於在 _ViewStart.cshtml 中已經指定了佈局。這個選項是用來重寫默認佈局文件的。

image

相關文章
相關標籤/搜索