[.NET MVC进阶系列03] Views 视图基础

时间:2021-01-15 16:47:15

[注:此文对应Chapter 3:Views]

  一、View的功能:

  1.View用来呈现页面UI,通过Controller来指定View:

   要注意的是,MVC和以前基于文件的Web应用不同,URL指向的并不是最终显示UI的文件,

     在MVC中,和URL打交道的是Controller,而不是View,是通过Controller中的Action Method来指定要显示的View

  2.Controller中指定View的规则:

在Controller中返回值类型为ActionResult的Action Method可以指定一个用来显示UI的View,

返回视图的代码:return View([参数]);

    返回View的View方法有三种不同参数,对应不同需求:

1)参数为空:return View()

    这种为最常用的格式,用来返回和Action方法名同名的默认视图;

2)参数为视图文件名:return View("HelloWorld.cshtml")

使用这种格式,可以将Action方法Url指向View/ControllName/HelloWorld.cshtml

    即,可以将Action方法Url指向View/ControllName下,和Action不同名的View文件

    3)参数为任意位置视图文件:return View("视图相对路径")

     在这种格式下,可以将Action方法对应的Url指向任意视图文件

   Controller代码:

 public class HomeController : Controller
{
public ActionResult Sample()
{
ViewBag.Message = "Hello World, this is a Sample!";
return View("~/Views/Shared/Error.cshtml");
}
}

   上面的代码中,HomeController的Action方法Sample(), 将Url: 域名/home/sample 指向了项目自动生成的Error视图

   运行程序得到的效果(注意地址):

[.NET MVC进阶系列03] Views 视图基础

   

   二、ViewData和ViewBag

    1.ViewData 

    原则上,controller中的数据是通过ViewDataDictionary(字典类)类的对象ViewData来传递给View 

    如:ViewData["CurrentTime"] = DataTime.Now;

    2.ViewBag

    从MVC3开始,将上面的语法进行简化,使用ViewBag动态包装ViewData,允许我们使用下面的语法:

      ViewBag.CurrentTime = DataTime.Now

    这种写法和上面的字典模式完全相同。

    注意:

    1)如果ViewBag.关键词其中的关键字中有空格,则不能编译通过;

    2)ViewBag不能直接作为动态参数进行传值

     如: @Html.TextBox("name",ViewBag.Name)——错误!

        @Html.TextBox("name",ViewData["Nmae"]) —— 正确!

        @Html.TextBox("name",(string)ViewBag.Name)——正确!

    

   三、基于强类型的View(Strongly Typed Views)

    1.原理:

    ViewData是ViewDataDictionary对象,该类不同于普通Dictionary类,其中包含了一个Model property,允许

    从Controller中,将一个(只能是一个)指定对象传到View中。

    这种方式不同于使用ViewBag,是强类型。不需要再进行类型指定,直接就可以使用该对象的属性和方法。

   2.使用:

    1)将要传到View中的对象作为参数给View()方法:

      如:return View(albums);

    2)在View中,用model接收该对象,直接包含新型信息,不需要再进行类型指定。

      @model IEnumerable<Album>

      <ul>

        @foreach(Album a in Model)

        { <li>@a.Title</li>}

      </ul>

     3.在View中添加命名空间引用

     1)直接在.cshtml文件中添加

      @using MvcMusicStore.Models

     2)在Views文件夹的web.config文件中添加,对整个Views文件夹中所有View都有效

      <pages pageBaseType="System.Web.Mvc.WebViewPage">

        <namespaces>

          。。。。

          <add namespace="MvcMusicStore.Models" />

        </namespaces>

      </pages>

    4.通过NuGet获取书籍配套例程代码:

     建好一个MVC4项目,【工具】——【库程序包管理器】——【程序包管理控制台】

     在命令行中键入:Install-Package Wrox.ProMvc4.Views.AlbumList

     [.NET MVC进阶系列03] Views 视图基础

     这将添加两个文件夹到项目中,Album类和AlbumController在\Samples\AlbumList中,视图文件Albums.cshtml在\View\Albums中

     对应的URL为:域名/albums/listweaklytyped和域名/albums/liststronglytyped

     分别非强类型和强类型方式访问,可以通过代码比较其区别

    

    四、View Models

    1.起因——Conroller默认只能传递一个强类型对象到View中:

     1)ViewData所继承的ViewDataDictrionary类中,只能包含一个Model类,所以,每次只能从Controlller传到View一个对象。

     2)View中,大多数情况下需要多个后台传过来的对象来进行绑定显示或操作,单个后台穿过来的类对象不够用,而使用ViewBag

      的话,又失去了强类型的好处。

    2.解决方案:View Modles

      写自定义的View modle class,将你需要的所有信息都包含其中。

     如:自定义一个购物车Modle类  

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

    这样,就可以把你需要的所有相关购物车的所有信息综合在一起传递给View,并且使用的强类型View方式

    @model  ShoppingCartViewModel

    接收到的就是从Controller传过来的完整信息。

    3. 例子:

     建好一个MVC4项目,【工具】——【库程序包管理器】——【程序包管理控制台】

     在命令行中键入:Install-Package Wrox.ProMvc4.Views.ViewModel

    执行成功后,同上面的例子,会在项目中增加两个文件夹:

      /Samples/ShoppingCartViewModel  包含Product类、ShoppingCartViewModel类和控制器ShoppingCartController类

        /Views/ShoppingCart/ 包含对应的视图Index.cshtml

      [.NET MVC进阶系列03] Views 视图基础

      运行后的效果(域名/ShoppingCart)

      [.NET MVC进阶系列03] Views 视图基础

  

    五、Razor View Engine

    简单的介绍跳过去,直接写核心的

    1. 代码表达方式

    最重要的标示符在Razor中就是“@”

    1)代码表达式

     如 :@对象名.属性  ,等同于Web Form视图中的<%: 对象名.属性 %>

     *注:

       虽然Razor比较智能,能够判断大多数情况,自动判定到底是想要转换后台代码,还是直接显示,

        但也会遇到混淆的时候,可以通过下面几种方式来避免:

       A) @(后台代码)

        通过给后台代码加(),来强制将@要转换的内容,和其后面要直接显示的文本分开。

         B) @@将显示为@文本

      2)HTML编码(Html Encoding)

      为防止注入攻击,Razor表达式会自动进行HTML编码

      @{string message = "<script>alert('haacked!');</script>";}

      <span>@message</span>

      上面的HMTL View代码在运行时会被解释为:

      <span>&lt;script&gt;alert('haacked!');&lt;/script&gt;</span>

        这种HTML编码是自动进行的。

      在某些情况下,需要取消HTML编码,可以使用HtmlHelp,使用HtmlStirng对象或者Html.Raw()

      如:

        @{string message = "<strong>This is bold!</strong>";}

        <span>@Html.Raw(message)</span>

      这次,就不会再被转码,会直接显示为:

      <span><strong>This is bold!</strong></span>

      另外,使用@Ajax.JavaScriptStringEncode来编码和Javascript相关的用户输入,来防止注入攻击,如:

<script type="text/javascript">
    $(function () {
        var message = 'Hello @Ajax.JavaScriptStringEncode(ViewBag.Username)';
        $("#message").html(message).show('slow');
    });
</script>

      3)代码段:

       @{代码段}

     2. Razor 语法:

     1)隐式代码表达式:

      <span>@model.Message</span>

      又Razor自动判断后面的.Message是text文本还是model的property

     2)显示代码表达式:

      <span>@(model).Message</span>

      在括号中的是后台代码,其外的是文本

     3)不经Html转码的表达式:

      <span>@Html.Raw(model.Message)</span>

      前面提过,Razor为防止注入攻击,自动对用户输入进行HTML转码,如果特殊情况下不用转码,需要写成上面的格式

    4)代码段:

      @{

          int  x = 123;

          string y = "hello!";

       }

    5)混合文本和标签

      @foreach(var item in items)

      {

        <span> Item @item.Name.</span>

      }

    6)混合代码和文本

     @if(showMessage)

      {

        <text>This is plain text </text>

      }

      或

     @if(showMessage)

      {

        @:This is plain text.

      }

     注意,后面的语法@:只能针对一行代码

    7)显示文本的@

     @ 或者 @@

    8)服务器端注释:

     @*

      This is a multiline server side comment.
      @if (showMessage) {
        <h1>@ViewBag.Message</h1>
      }
      All of this is commented out.
     *@

    9)调用泛型函数(Generic Method)

     @(Html.SomeMethod<AType>()) 

     其实和显式的Razor代码表达式一样,注意外面加()!

    3. Layouts 布局

    类似于Asp.net中的MasterPage(母板页),用来设定统一外观的。

    设定整体布局使用的是~/_ViewStart.cshtml,它会在所有View被加载之前加载,指定母版布局视图

@{
Layout = "~/Views/Shared/_Layout.cshtml";
}

    每个View下Controller对应的文件夹中,可以添加自己的_ViewStart.cshtml,用来指定独自使用的布局视图,采取就近原则(替View代根目录中的);

    而且,Layout框架的赋值语句:Layout="。。。",也可以加到任意一个View文件中,作为此文件的单独布局框架。

    1)@RenderBody()

    Layout Template View中的@RenderBody()用于占位。

    2)@RenderSection()

    一个Layout可以包含多个分块(setions),例如,可以为Layout添加Footer分块

    <footer>@RenderSection("Footer")</footer>

    在使用这个Layout的View中,需要加入@section Footer{..}代码,来设置自己的footer,如:

    @section Footer{ @@Copyright 2001-2015, All Right Received. }

    但是,大多数时候,希望section都是可选的,可将其改为:

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

    更为通用的方式,是在设置可更改的Section时,配备一个默认的Section外观:

    <footer>

      @if (IsSctionDefined("Footer"))

      {

        RenderSection("Footer");

      }

      else

      {

        <span>This is the default footer. </span>

      }

    </footer>

    

    六、Patial View

    部分View是不包含layout的局部View。

    通常用来作为配合Ajax进行局部刷新。

    例子:

      Install-Package Wrox.ProMvc4.Views.SpecifyingViews