Model Binding-ViewBag ViewData ViewData.Mode TempData

 

資料從Controller如何傳給View的技術稱之為Model Binding,

此文章主要說明Model Binding、ViewBag、ViewData、ViewData.Mode、TempData的使用。

 

一、Model Binding的舉例

1、首先先新增一個預設的MVC專案

2、於Controller準備一個Model,帶給View的datatime

public ActionResult Index()
{
    return View(DateTime.Now.AddDays(-1d));
}

3、View先不呼叫helper,先改成如下

@model DateTime?

@Model

4、執行畫面為

5、接下來使用helper(@Html.DisplayFor()),View改為強型別

@model DateTime?

@Html.DisplayFor(model => model)

6、執行畫面為

會發現html呈現都一樣,可知此@Html.DisplayFor()只負責將資料輸出成字串而已

7、心得

注意:@Model相等於DisplayFor()擴充方法裡的model變數,

初期我看保哥的書完全搞混不知道@Model、@model、model的差別,

自己慢慢學習之後,現在懂了,@Model就是用來接收從Controller傳來的模型資料、

@model為指示詞表示所接到的模型資料型態為何、而存在於擴充方法裡的model只是個變數,

並不是關鍵字,而該變數其實就是@Model經由委派傳給model變數來處理的。

其中牽扯到的技術,是基本功,我知道很複雜,但知道來龍去脈時,

我只能說「超爽der~~~」

 

二、ViewBag

當Controller為

public ActionResult About()
{
    ViewBag.Message = "Your application description page.";

    return View("~/Views/Home/About.cshtml");
}

View為

<h3>@ViewBag.Message</h3>

<p>Use this area to provide additional information.</p>

則@ViewBag.Message將會等於Your application description page.

 

ViewBag 值的型別是 object,如果你的 object 的內容是可以轉成字串,

那你就可以將之轉成字串型別,並可操作字串方法了,如下

var myBoolValue = @Viewbag.MyBoolValue.ToString().ToLower();

 

三、ViewData

1、預設以字串傳遞

當Controller為

public ActionResult About()
{
    ViewData["context"] = "a word";

    return View();
}

View為


<h3>@ViewData["context"]</h3>

<p>Use this area to provide additional information.</p>

則@ViewData["context"]將會等於a word

 

2、以非字串傳遞須轉型

(1)、另一個例子,當ViewData內容非字串時

當Controller為

public ActionResult About()
{
    ViewData["the_bool"] = true;

    return View();
}

此ViewData為弱型別,所以ViewData必須明確轉型

@{
    bool? myBoolean = (bool?)@ViewData["the_bool"];
}

@{
    if (myBoolean != null)
    {
        <p>boolean 值為@(ViewData["the_bool"])</p>
    }
}

(2)、承上例,但View此次使用 as 關鍵字轉型

@{
    bool? myBoolean = @ViewData["the_bool"] as bool?;
    myBoolean = myBoolean ?? false;
}

@if (myBoolean != null)
{
    <p>boolean 值為@(ViewData["the_bool"])</p>
}

 

3、或使用dynamic來宣告,dynamic關鍵字在編譯時被視為實際型別,

而被宣告的型別物件(myBoolean)又可在執行時期自動轉成目標型別。

<p>Use this area to provide additional information.</p>
@{
    dynamic myBoolean = @ViewData["the_bool"];
}

@{
    if (myBoolean != null)
    {
        <p>boolean 值為@(ViewData["the_bool"])</p>
    }
}

成功畫面為

否則會出現錯誤

 

4、ViewData可與ViewBag互相透通

(1)單純傳遞字串時可互相透通

例如:

Controller為

public ActionResult About()
{
    ViewBag.Message = "Your application description page.";

    return View();
}

View可為

@ViewData["Message"]

反過來

Controller為

public ActionResult About()
{
    ViewData["Message"] = "Your application description page.";

    return View();
}

View可為

@ViewBag.Message

(2)如果是傳遞物件時

於View裡使用ViewBag還算順利,因為ViewBag會幫你自動轉型

在Model準備

namespace WebApplication1.Models
{
    public class product
    {
        public string Id;
        public string name;

        public product(string a, string b)
        {
            Id = a;
            name = b;
        }
    }
}

Controller準備

using System.Web.Mvc;
using WebApplication1.Models;

namespace WebApplication1.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            product flower = new product("000","flower");

            ViewData["Thing"] = flower;

            return View();
        }
    }
}  

View可為

@ViewBag.Thing.Id

但反過來可沒那麼順利了,使用ViewData時必須要手動轉型才可

Controller改為

using System.Web.Mvc;
using WebApplication1.Models;

namespace WebApplication1.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            product flower = new product("000","flower");

            ViewBag.Thing = flower;

            return View();
        }
    }
}

View改為

@{
    var Thing = ViewData["Thing"] as WebApplication1.Models.product;
}

@Thing.Id

 

5、ViewData特性

ViewData有一個特性,就是他只會存在這次的Http中要求而已。

ViewData只在當前的Action中有效,生命週期和View相同。

 

四、ViewData.Model

1、一般字串

Controller為

public ActionResult Contact()
{
    List<string> aList = new List<string>();
    aList.Add("List A");
    aList.Add("List B");

    ViewData.Model = aList;

    return View();
}

View為


@model List<string>

@{
    foreach (var item in @Model)
    {
        <p>@item</p>
    }
}

上述ViewData.Model的@model宣告為強型別

ViewData.Model等於ViewPage的Model

也就是Controller可改寫為

 public ActionResult Contact()
 {
     List<string> aList = new List<string>();
     aList.Add("List A");
     aList.Add("List B");

     return View(aList);
 }

2、另一例子為加入類別並使用強型別來帶出資料

準備一個Model為

namespace WebApplication1.Models
{
    public class product
    {
        public string Id;
        public string name;

        public product(string a, string b)
        {
            Id = a;
            name = b;
        }
    }
}

準備Controller為

using System.Collections.Generic;
using System.Web.Mvc;
using WebApplication1.Models;

namespace WebApplication1.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            List<product> aList = new List<product>();

            product p = new product("a","b");
            aList.Add(p);

            return View(aList);
        }
    }
}

而View為

@model List<WebApplication1.Models.product>

@Model.FirstOrDefault().Id

畫面為

此例子就可充分利用Intellisense的好處了

 

五、TempData

1、TempData只能被取用一次,用完即被清除。

Controller為

public ActionResult Contact()
{
    List<string> aList = new List<string>();
    aList.Add("List A");
    aList.Add("List B");

    TempData["myData"] = aList;
    TempData["message"] = "我是Message";

    return View();
}

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

Contact view為


@{
    List<string> aList = (List<string>)TempData["myData"];
}
@{
    foreach (var item in aList)
    {
        <p>@item</p>
    }
}
@Html.ActionLink("About", "About")
<p>已取用myData,但未取用message</p>

About view為

@{
    List<string> aList = (List<string>)TempData["myData"];
}
@{
    if (aList != null)
    {
        foreach (var item in aList)
        {
            <p>@item</p>
        }
    }
}
@TempData["message"]
<p>已取用的myData會被清除,但未取用過的message會秀出</p>

2、如果TempData被讀取了,但不想要被刪除如何做?

可以在使用TempData資料後,再使用TempData.Keep();方法,

可保住所有session值,如果只想保留特定值的話,

則可使用TempData.Keep(string Key)方法;

承上例,View可改為

@{
    List<string> aList = (List<string>)TempData["myData"];
    TempData.Keep();
}
@{
    if (aList != null)
    {
        foreach (var item in aList)
        {
            <p>@item</p>
        }
    }
}
@TempData["message"]

 

參考資料:

MVC中 ViewData、ViewBag、TempData的区别与联系

[ASP.NET MVC] ASP.NET MVC 傳遞資料容器(三) - 總結