知识点3-4:给视图传递数据

    控制器中加工处理好的数据,如何传递给视图? 

一、ViewDataDictionary

    用来将模型信息传递给视图的主要对象是ViewDataDictionary类,它暴露了一个字典,以使控制器动作能够把任意数目的模型对象和信息传递给视图。借助字典对象,我们可以传递需要的数据到视图。

    举个栗子>>:如何扩展留言本网站,使任何人都能查看留言,但只有当前已登录用户能够编辑留言本条目。

    目前显示留言本信息,我们可以把GuestbookEntry形式的对象直接传递给视图,GuestbookEntry如下所示。

public class GuestbookEntry
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Message { get; set; }
        public DateTime DateAdded { get; set; }
    }

    尽管这个GuestbookEntry类拥有显示GuestbookEntry所需的全部信息,但它并未包含当前已登录用户的任何信息,或指示视图是否应该显示Edit链接的信息。这就需要给视图提供更多数据,而不只是GuestbookEntry对象。我们可以使用ViewDataDictionary来提供这种额外的信息片段,如下所示。

        public ViewResult Show(int id)
        {
            var entry = _db.Entries.Find(id);
            bool hasPermission = User.Identity.Name == entry.Name;
            ViewData["hasPermission"] = hasPermission;
            return View(entry);
        }

    上例检查了当前用户名,将它与留言本条目的Name属性进行比较,并将比较结果放入用hasPermission键表示的ViewData中。接着用重载的View方法创建一个ViewResult对象,并将ViewData的Model属性设置为GuestbookEntry对象。

    在视图一侧,我们将取出ViewData中的hasPermission信息,并用它隐藏Edit链接,如下所示。

<h2>Guestbook Entry</h2>
<dl>
    <dt>Name:</dt>
    <dd>@Model.Name</dd>

    <dt>Data added:</dt>
    <dd>@Model.DateAdded</dd>

    <dt>Message:</dt>
    <dd>@Model.Message</dd>
</dl>
<p>
    @{
        bool hasPermission = (bool)ViewData["hasPermission"];
        if(hasPermission)
        {
            @Html.ActionLink("Edit","Edit", new { id=Model.Id})
        }
        @Html.ActionLink("Back to Entries", "Index")
    }
</p>

    在这个视图中,我们从ViewData提取了hasPermission信息。接着,根据hasPermission变量,有条件地显示了Edit链接。最后,显示了一个将用户带回留言本条目列表页面的链接。显示留言本条目的最终渲染页面如下图所示。

    虽然ViewDataDictionary非常灵活,但在语法上并不太好用,只要从字典接受数据,就必须执行类型转换。

二、ViewBag

    与ViewDataDictionary一样,ViewBag也提供了一种方式,以便将数据从控制器传递给视图,但ViewBag利用了C#4的动态语言特性。它并非使用字符串键在一个字典中存储数据项,你可以在控制器中简单地在这个动态的ViewBag属性上设置若干属性:

ViewBag.HasPermission = hasPermission;

    ViewBag属性在视图中也是可用的,因此不必从ViewData接受数据项,并将它转换成Boolean型,我们可以简化视图,直接访问ViewBag:

<p>
    @if(ViewBag.HasPermission)
        {
            @Html.ActionLink("Edit","Edit", new { id=Model.Id})
        }
        @Html.ActionLink("Back to Entries", "Index")
    }
</p>

    尽管ViewData和ViewBag这两种动态方法都提供了许多灵活性,但这是有代价的。如果偶然输错了一个动态属性名,这些技术既不能友好重构,编译器也不能测出这类错误。此外,对于动态属性或ViewData,你得不到Visual Studio的智能感应。

    另外,你不能方便地将元数据附加到动态属性上。模型验证规则也不能用于动态的ViewBag属性。作为一种可选办法,你可以利用强类型视图,以指示视图能够使用一个特定的已知强类型类。这样可以利用智能感应和Visual Studio的重构工具,并且也可以使用模型验证规则。

三、带有视图模型的强类型视图

    在使用基于Razor的视图时,默认情况下,视图继承于两种类型:System.Web.Mvc.WebViewPage或System.Web.Mvc.WebViewPage<T>,继承于WebViewPage的视图称为弱类型视图,继承与WebViewPage<T>的视图为强类型视图。

    WebViewPage<T>的定义如下所示。

    除了通过Model属性提供对ViewData.Model的强类型封装之外,还对相关的视图辅助器对象AjaxHelper和HtmlHelper的强类型版本提供了访问。为了使用强类型视图,首先必须确保控制器动作适当地设置了ViewData.Model。

    练习>>:将Guestbook程序中的Index视图修改为强类型视图。

    在清单3.4中,为了显示列表页面,我们接受了留言本的所有条目,并将整个资料集合传递View方法,该方法封装了对ViewData.Model属性的设置。

清单3.4 将留言条目集合传递给视图

        public ActionResult Index()
        {
            var mostRecentEntries = (from entry in _db.Entries
                                     orderby entry.DateAdded descending
                                     select entry).Take(20);

            var model = mostRecentEntries.ToList();
            return View(model);
        }

    在与这个动作对应的Index视图中,即使松散类型的WebViewPage类也能够使用这个ViewData.Model属性。但该属性却是object型的,需要对它进行转换才能有效地使用它。与此相反,我们可以通过使用@model关键字,为WebViewPage<T>基类指定模型类型。

@using Guestbook.Models
@model List<GuestbookEntry>

@{
    ViewBag.Title = "查看留言";
}

<h2>请给我留言吧</h2>
<p>
    <a href="/Guestbook/Create">添加留言</a>
</p>
@foreach(var entry in Model)
{
    <section class="contact">     
        <header>
            <b>作者:</b>@entry.Name; <b>时间:</b>@entry.DateAdded.ToLongDateString()
        </header> 
        <p><b>留言内容:</b>@entry.Message</p>
    </section>
    <hr />
}

    通过使用@model关键字指定模型类型,视图便是继承于WebViewPage<T>,而不是WebViewPage了,于是得到了一个强类型视图。这里还使用了@using关键字,以导入命名空间。

总结>>:从Action取得数据,在ASP.NET MVC可区分成两种方式,一种是“使用弱类型取得数据”,另一种则是“使用强类型取得数据”,两者的差别在于View页面最上方声明的方式。

    如果View页面使用弱类型接收来自Controller的数据,在View页面里完全不需要有任何声明,数据可以从ViewData、ViewBag或TempData取得,在页面中也可以通过@Model属性,取得从Action传来的ViewData.Model数据模型,但@Model数据模型的类型将会是object,所以算是弱类型的传值方式。

    如果View页面使用强类型方式接收来自Controller的数据,那么,必须在View页面的第一行使用@model关键字引入一个View页面专用的数据模型类型参考。使用这种方式有助于提升View的开发效率,因为可以使用Visual Studio 2012的Intellisense提示功能。

posted @ 2014-09-28 22:52  liesl  阅读(534)  评论(0编辑  收藏  举报