ASP.NET MVC4 IN ACTION学习笔记第二波


ASPNET MVC4 视图基础(Views fundamentals)

--忽然发现我的时间不够了,但是我还是完成了

image原著:ASP.NET MVC 4 IN ACTION

本人能力有限,尽量将书中的知识浓缩去讲,仔细学过后,然后你再学习其他语言的MVC框架也就大同小异了

本次覆盖知识点:

  1. 1. 把数据传递给视图 (Providing data to the view )
  2. 2. 使用强类型视图 (Using strongly typed views)
  3. 3. 使用视图助手对象 (Understanding view helper objects)
  4. 4. 用模版 (Developing with templates)

      视图(Views)是ASP.NET MVC 应用程序起决定性的一部分--它提供了一个很简洁的方式,在你的应用程序中,逻辑中涉及到展现页面的部分分离出来了。在上一章中的我们的Guestbook应用程序中,我们用Razor模版引擎写了一些简单的视图,稍微了解了一点,最后,我们学习了layouts是如何让你的应用程序中的所有页面保持一致的风格,结束了上章的课程。

没有学过的,上章飞机票:

      在本章中,我们将再稍微深入学习一下视图---我们将会研究一下ASP.NET MVC如何呈现视图,然后我们再看下把数据传给视图的其他不同的一些方法。最后,我们再讲一下原来在 ASP.NET MVC 2 中介绍过的一些模版(temlate)特征,为了分析讲解这些特征,我们一开始就会在我们的Guestbook应用程序中添加一个编辑页面。

3.1  视图介绍

    视图的职责看似简单。它的目标是与相对应的模型(Model)相关联,并使用对应的模型来呈现内容。由于控制器(Controller)和相关联的服务已经处理了所有的业务逻辑,并且把处理后的结果封装成了模型对象,而视图只需要知道怎样把这个模型转换成HTML来呈现就行了。

   尽管这种职责关系的分离可能,对传统的ASP.NET应用程序编程人员来说编写造成了麻烦和困扰,但是视图你还是要编写的。为了保证你的视图不会太复杂而很难去维护,所以对于视图,你还是要小心仔细的,要有意的去设计它.

   在我们学习“如何把数据传递给视图”的方法之前,我们先研究一下MVC框架是怎样把视图给呈现的。

   3.1.1 选择一个视图去展示

     在上一章里面我们通过调用一个控制器里面的一个action中的一个View方法来让页面呈现了。下面这个是我们的GuestbookController控制器里的Create操作:

     image

   通过这些代码, Views/Guestbook/Create.csthml 这个视图文件就会被呈现。但是在这个应用程序中,MVC框架怎么知道去呈现这个指定的视图,而不是其他视图,比如说Index.cshtml的呢?

   调用View方法将会返回一个 知道怎么去呈现指定的视图的ViewResult对象。当调用View的无参数方法时,MVC框架就会认为你要呈现的视图的名字跟这个方法所在的action(Create)名字一样。之后,MVC框架的ControllerActionInvoker类就会去调用ViewResult类,然后把呈现页面的责任转交给了它。在这个时候,这个框架也会命令ViewEngineCollection去查找要呈现的页面的位置。(回顾一下上一章的内容。这个视图引擎默认会在 Views/<Controller Name>目录和Views/Shared目录)

   视图引擎

    不同的视图引擎会有它不同的格式去呈现视图,默认 ASP.NET MVC有两个视图引擎-RazorViewEngine和WebFormViewEngine。Razor视图引擎的格式是cshtml文件或者vbhtml文件,然而WebForm视图引擎依旧支持老格式的Web Form视图(aspx页面和.ascx文件)。以前的ASP.NET MVC版本默认都只包括WebForm视图引擎。

    为什么在ASP.NET MVC3中要引入新的视图引擎呢?随着ASP.NET 1.0的发行的开始,Web Form就允许把代码和标签写在一个aspx页面里面,但是把C#代码写在aspx页面里面,控件的逻辑写法在通常的开发中严重受到阻碍。取而代之的是,开发者们努力去把所有的逻辑放在了页面的后面(代码后置)。随着ASP.NET 的发布,在aspx文件中增加了数据绑定,其他更新的模块都去适应配合控件开发的模式。

    在许多MVC的框架里,视图开发都鼓励和要求代码,直接用标签去写(也就是不用控件),由于ASPX视图引擎在设计时没有达到这个目标,所以ASP.NET团队决定去设计一个全新的视图引擎--把代码写在模版里的一种模式。这是一种更智能的引擎,引擎能够很容易地识别出标签的开始和结束,而且开发者也不用写的那么复杂。

当然你也可以用别的第三方的视图引擎,在第10章,我们就会去看一下现在比较流行的Spark视图引擎。

   3.1.1 重写View

      如果你不想你的视图名字跟action一样。你可以使用View的重载方法。例如

     return View("New");   查找路径 Views/<Controller Name>/New.cshtml和Views/Shared目录,而不再是action的名字了

     你还可以写路径,就可以脱离默认的控制名了的路径限制了

     return View(("~/Views/SomeOtherDirectory/New.cshtml");

   3.1.2 把数据传给视图

      我们还是在我们的Guestbook案例上继续编写。上篇代码案例

     我们将要讲一下把数据传给视图的3种不同的方法---ViewDataDictionary,ViewBag,强类型视图

   3.2.1 ViewDataDictionary

      把数据传递给视图过去经常使用的最主要的对象就是ViewDataDictionary

     和其他MVC框架一样,ASP.NET MVC也暴露一个集合:可以把更多的model对象传递给视图使用,然后视图可以利用model里面封装好的信息来展示信息。

     比如说,我们可以拓展我们的guestbook页面---所有人都可以查看guestbook,但是只有当前登录的用户可以编辑guestbook entries(guestbook中的一个实体对象,也就是一条记录)。为了可以达到这个目的,我们可以通过GuestbookEntry对象,代码如下:

     image

    尽管,这个GuestbookEntry类已经包括了所有我们要在使用GuestbookEntry的页面上展示的数据了,但是它不包括当前登录的用户的信息,或者不能决定视图是否显示Edit超链接。我们需要给视图更多的信息,不能仅仅靠GuestbookEntry来做这个决定。我们可以使用ViewDataDictionary来提供更多的信息,代码如下

public ActionResult Show(int id) {
            var entry = _db.Entries.Find(id);  //找到该Id的Entries
            bool hasPermission = User.Identity.Name == entry.name; //如果登陆人的姓名等于entry录入人的姓名,就显示Edit按钮
            ViewData["hasPermission"] = hasPermission;
            return View(entry);
        }

添加到Controllers/GuestbookController.cs这个文件里面

imageimage

在Controller里面我们可以直接使用ViewData,因为Controller继承ControllerBase类,ControllerBase下面有ViewData属性。我们通过比较GuestbookEntry的name和当前登录用户的name是否一样,然后比较结果放在hasPermission里面,然后视图那边查看hasPermission是true还是false来决定是否显示Edit超链接。

添加Show视图,右键action名称,添加视图,然后直接点添加

image

视图里面代码如下:

@{
    ViewBag.Title = "Show";
}
 
<p>
    @{
        bool hasPermission = (bool)ViewData["hasPermission"];
    }
    @if (hasPermission)
    { 
        @Html.ActionLink("Edit", "Edit", new { id = Model.Id });
    }
    @Html.ActionLink("返回 Entries","Index")
</p>
 
 

现在我们来运行我们的项目:如果是从我的csdn上下载的,默认里面有3条数据了。

运行的时候,我们手动在地址栏的后面输入Guestbook/Show/1,其中1是entry的id号,在controller里面我们不是留了一个参数吗?在Asp.NET MVC中,你可以这样传递参数,完整模拟路径如下

http://localhost:端口号/Guestbook/Show/1

跳转后,页面默认如下:因为你还没有登录,所以不会显示Edit超链接

数据库中的表数据一览,目前id只有1,2,3,所以测试的时候,不要输入其他的

image

 

①输入地址后,显示效果如下

image

测试我们先注册一个用户,名字叫 茗洋芳竹,密码叫123456

image

注册好了,会自动登陆

image

输入Show/2,因为id=2的信息是  name等于茗洋芳竹,是本人,所以显示了Edit超链接

 

 image
 

我猜想,如果你以前做过WebForm的话,聪明的你肯定已经领悟出来什么了.

 

3.2.2 ViewBag

    ViewDataDictionary一样,ViewBag也是把数据传递给视图使用的一种手段.ViewBag使用了C#4.0中的 的dynamic语法.

它不是使用key字符串在集合里存储对象了,你可以在你的controller中简单的设置一下dynamic类型的ViewBag的一个属性.

image

hasPermission是ViewBag的一个根本不存在的属性,这里名字随便取,因为ViewBag是个dynamic类型的.不懂dynamic的可以查看一下C# dynamic资料

如果采用ViewBag的方式

那么Show页面稍微改下就行了

原本代码是这样的image

 

bool那里面的代码可以不要了,if后面的那个条件,直接改成

image

就行了.

估计ViewBag你已经会用了,Model从哪里来的,你先不用管,估计你也猜到了,我们在Controller中调用View()方法的时候,加了一个实体对象作为参数.那么这里你就可以用Model来等效于你后台传来的实体对象那样使用就行了.

尽管ViewData和ViewBag的都为解决数据传递视图的问题而提供了很多的灵活性,但是也因此付出了很大的代价.如果你偶尔把一个dynamic属性名称敲写错了,编译的时候是找不到错误的,这些技术所以也有不友好的地方.除此之外,在Visual Studio中 dynamic的属性,编写代码时候是没有提示的,ViewData也没有,你要记得ViewData中的键名称。(尽管有第三方企业工具:比如说JetBrains ReSharper可以支持它)

 

除此之外,你也不能很容易地在dynamic属性上绑定元数据.而在ASP.NET MVC框架里面,你可以利用特性的优势,直接把元数据绑定到现在比较常用的类型上(比如说,在System.ComponentModel.DataAnnotations命名空间下的验证特性,你可以用来标记一个字段是否不能为空(required),一个字段的长度限制等等),这些特性在dynamic的ViewBag属性上都是不能使用的

取而代之的是,你可以使用强类型视图,一个使用了强类型类的视图.通过这个方法,你就可以利用vs获得智能感知和vs的的重构工具来高效快速的写代码了.你也可以用特性驱动元数据的方法获得好处.在下一节我们来研究一下.

 

3.2.3 强类型视图,一个视图模型

 当你使用基于Razor的视图的时候,你的视图可以继承两种类型,默认的是System.Web.Mvc.WebViewPage或者System.Web.Mvc.WebViewPage<T>,WebViewPage<T>继承WebViewPage,所以提供了一些WebViewPage没有的一些特征.

  下面是 WebViewPage<T>内部骨架(Skeleton)的一些定义

image

 

  除了提供了强类型的ViewData.Model的包装,然后你就可以使用Model外,WebViewPage<T>还提供了两个可以在视图中可以使用的AjaxHelper和HtmlHelper对象.

   为了使用强类型视图,首先你要在你的Controller的action中设置ViewData.Model属性,在Listing 3.4中,我们查出了所有的guestbook entries,然后展示在列表页面上,在View方法中我们传递了一个实体.换句话说,也就是换个形式封装设置了ViewData.Model属性了,所以你在视图页面就可以直接使用Model属性了.

image

 

我们修改GuestbookController中的Index操作和相对应的视图页面(Guestbook/Index.cshtml)

image

 在Index视图上就是用这个Action的.即使是一个弱类型的WebViewPage类,但是也可以使用ViewData.Model属性的.但是这个属性是一个类型对象,我们需要转换一下结果才能有效的使用.取而代之,我们可以使用@model关键字来使我们的父类WebViewPage<T>指定model类型

  • @using GuestInfo.Models
  • @model List<GuestbookEntry>

通过使用@model关键字我们指定了model的类型,现在我们的视图已经继承了于WebViewPage<T>而不是WebViewPage了.现在我们已经有了一个强类型的视图了.我们也可以使用@using关键字导入命名空间.在下一节里,我们将要看一下,在一个视图里我们怎样使用model对象来展示信息.

image

3.2.4 在一个视图里面展示视图model的数据

        在一个视图里面展示信息,通常的,你可能使用HtmlHelper对象去辅助让这个model生成html,思考一下下面一个展示了一个完整的Guestbook entry信息的代码,这个代码写在Views/Guestbook/Show.cshtml

<h2>Guestbook Entry</h2>
<dl>
    <dt>姓名:</dt>
    <dd>@Model.Name</dd>
    <dt>日期:</dt>
    <dd>@Model.DateAdded</dd>
    <dt>消息:</dt>
    <dd>@Model.Message</dd>
</dl>
<p>
    @{
        bool hasPermission = (bool)ViewData["hasPermission"];
 
    }
    @if (ViewBag.hasPermission) //       ViewBag.hasPermission
    { 
        @Html.ActionLink("Edit", "Edit", new { id = Model.Id });
    }
    @Html.ActionLink("返回 Entries", "Index")
</p>

上面这段代码我相信你们应该能看懂了.看不懂的,在评价里面说一下

当我们在屏幕上展示未编码的用户输入的信息的时候,我们宁可不留出存在多种脚本攻击的可能性.还好这个数据在呈现于屏幕之前已经自动编码了.如果你想展示一个没有编码过的文本,你可以使用Html.Raw方法来使那些信息以纯文本的形式展现.

在login页面里面,我们使用一个视图model对象来表达了一个表单的全部的数据,代码如下

image

这个登陆页面也非常简单,如下

image

由于在Log on屏幕里,我们选择一个强类型视图,我们使用了内置的助手去帮助为每一个节点生成html.为了替换掉使用弱绑定来呈现action的参数,我们可以使用基于表达式的HtmlHelper拓展来创建不同类型的input节点,代码如下(Views/Accout/register.cshtml)

@model GuestInfo.Models.RegisterModel
@{
    ViewBag.Title = "注册";
}
 
<hgroup class="title">
    <h1>@ViewBag.Title.</h1>
    <h2>创建新帐户。</h2>
</hgroup>
 
@using (Html.BeginForm()) {
    @Html.AntiForgeryToken()
    @Html.ValidationSummary()
 
    <fieldset>
        <legend>注册表单</legend>
        <ol>
            <li>
                @Html.LabelFor(m => m.UserName)
                @Html.TextBoxFor(m => m.UserName)
            </li>
            <li>
                @Html.LabelFor(m => m.Password)
                @Html.PasswordFor(m => m.Password)
            </li>
            <li>
                @Html.LabelFor(m => m.ConfirmPassword)
                @Html.PasswordFor(m => m.ConfirmPassword)
            </li>
        </ol>
        <input type="submit" value="注册" />
    </fieldset>
}
 
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

其中这段代码image

功能类似于

<label for=”UserName”>姓名</label>

<input id=”UserName” name=”UserName” type=”text” value=”” />

由于这个label和input都可以用表达式(expression)来生成,所以我们不用再记复杂的label和input名称了

HtmlHelper被设计时就支持强类型视图

image

由于我们的表单都是使用强类型视图生成的,所以我们在controller中可以好好设计action,让这个表单可以post提交上去.

而不是列举每一个input字段作为一个action方法的参数,我们可以绑定所有的参数给同一个view model(我们曾经想要展现的视图)

image

在这里可以有两个参数,当然你也可以有多个.这里你也看到了,这里有个returnUrl,而不是表单中input节点.第一个参数,是一个model,封装好了所有input中的值

随着HtmlHelper对强类型视图支持的越来越好,如果你只是仅仅依靠这些拓展来生成HTML,那么在你的视图里面就会有一些重复.举个例子,如果每个input节点都想要一个对应的label,那么为什么不能包括它呢?每一个用户接口都是不一样的.ASP.NET MVC团队不能猜对每个使用的input和label的布局的人想要什么样的布局(layout).虽然每一个input节点都应该有有个label.但是这个现存的helper方法可以创建那些不需要label的input节点.相反的,我们可以使用ASP.NET MVC2中的特征的优点--模版--去掌握一个更标准化的html的生成方式

3.2.4 使用强类型模版

     如果你现在已经转向用基于表现层的model形式的强类型视图模式开发,那么你将要开始发现越来越多的句式出现了。如果你的表现层model对象在表单里有个boolean属性,你肯定会去使用checkbox在表单里面呈现。Email地址,password字段等等都是的。input节点没有对应的验证信息是很少出现的。

      除了使用HtmlHelper以外,在ASP.NET MVC2开始出现的时候,templated helpers新的特性出现了,它被设计基于强类型视图用来辅助设计生成html的一个技术。Templated helper可以为一个完整的model生成html或者为一个member生成html。

  

3.3.1 EditFor和DisplayFor 模版

    这两个不同的模版集被分成了编辑(editor)和展现(display)模版。这个编辑和展现的模版有下面代码生成

image

  虽然在使用模版,同样效果用字符串方式的方法对弱类型的视图不利,但是我们可以使用基于表达式的方法来在强类型视图里面获得优势(lambda表达式语法)。如果我们的model比较简单,我们可以使用ForModel系列的方法,它会重复遍历model中的每一个成员(

member),然后生成html。

  在我们的修改密码的页面上布局比较简单,我们可以使用EditorForModel方法来生成一个用于编辑信息的表单

  ①我们在Models/AccountModels.cs里面我们先添加一个类

    image

这个代码和LocalPasswordModel代码一样的,我们复制一下代码改一下名字。

虽然已经有了更改密码的页面了,但是这里我们只是练习一下EditorForModel的用法,还希望不用嫌麻烦

接下来我们在Controller/AccountController.cs用法

添加一个Action

  public ActionResult ChangePasswordPage() {
            ChangePasswordModel newPassword = new ChangePasswordModel();
            return View(newPassword);
        }
 
接下来我们右键该action名字,添加一个视图。
视图代码如下:
@{
    ViewBag.Title = "ChangePasswordPage";
}
@using (Html.BeginForm())
{ 
  <div>
      <fieldset>
          <legend>用户信息</legend>
          @Html.EditorForModel();
          <p><input type="submit" value="改变密码"/></p>
      </fieldset>
 
  </div>  
}
 
 
接下来按F5运行,可能首先你要登陆一下
 
登陆:
image
 
登陆成功后,我们先看一下原配的,点击一下你的名字,进入更改密码界面
image
image
 
接下来我们修改一下地址栏
image
 
EditorForModel方法会在所在的view上循环对应model中所有的member(成员),会为每个成员生成editor模版,我自己觉得这个也不怎么常用吧。文本框上面的文字,来自ChangePasswordModel类
image
 
 
但是有时,我们不可能只要这么简单的输出html,为了更灵活,比如说我们调整布局,或者添加更多的html标签等等
接下来我们使用EditorFor模版
image效果如下,发现只有含有验证功能的文本框
 
image
 
当然,你把EditorFor改成Editor也行,只不过有的名称你可能记不住,所以说For系列的模版,例如EditorFor而不是Editor,所以正确性更高
代码如下
image
 
 
3.3.2 内置模版
    不出所料,ASP.NET MVC有一套自己的编辑和展示的模版,大致如下
    image
 
 
除了Collection和Object模版,其他的模版都呈现的是唯一的值,Object模版循环访问ModelMetadata.Properties集合中的每一项,每一项展现的时候都调用对应的display模版.Collection模版循环访问model对象中的每一项,并为列表中的每一项调用对应的display模版显示。
正如你预料到的,展示模版在浏览器中呈现为一个节点,例如纯文本或者一个锚标签,相反地,editor(编辑)模版展现的是表单中的节点,默认的编辑模版在表3.3都列出来了
image
 

3.3.3 查找模版

editor模版和display模版助手方法(helper methods)都是通过名字查找对应的模版.模版的名字的值也是有来源的.模版助手方法根据这个名字,然后用明确的算法找到对应的模版并呈现。一旦匹配找到了,就会立即去呈现内容。模版助手方法在根据下一个模版名字查找之前,会根据明确的路径查找模版。查找的路径是EditorTemplates和DisplayTemplates文件夹。跟控制器找视图有点像.如果一个助手方法在一个明确域(area)的视图里面被使用了,被查找的文件夹可能是:
 
<Area>/<ControllerName>/EditorTemplates/<TemplateName>.cshtml(或者.vbhtml)<Area>/Shared/EditorTemplates/<TemplateName>.cshtml(或者.vbhtml)
 
如果模版不在这些文件夹里,或者视图不在域里,这个默认的视图查询地址就会被使用
 
<ControllerName>/EditorTemplates/<TemplateName>.cshtml(或者.vbhtml)Shared/EditorTemplates/<TemplateName>.cshtml(或者.vbhtml)
  •  
  • 关于模版的查找是遵循算法的
  • image
 
举个例子:

我们现在要在更改密码页面上展现一个自定义的ChangePasswordModel模版。model我们已经有了,现在我们只需要定义一个更model类型名字(ChangePasswordModel)一样的模版就行了。文件放的路径如下图

imageimage

左边一个,只给AccountController使用,右边一个,所有的控制器都可以使用,EditorTemplates文件夹是自己建立的

 
 
3.3.4 自定义模版(难)
 
总而言之,有两种理由去创建一个自定义模版

■ 创建一个自定义模版 ■ 重写现有的模版

 
首先我们看一下在控制器明确的视图文件夹下的模版解决方案规则,因此我们能够很明确的在Shared文件夹下重写一个内置的模版,然后我们在重写控制器明确的视图文件夹里。
解释一下“控制器明确的视图文件夹”:例如GuestController这个就是控制器明确了,名字是Guest,所以我们能找到对应的视图文件夹,例如 Views/Guest/…   这个最终的文件夹路径就是  控制器明确的视图文件夹
打个比方,你可能有一个应用广泛的模板,用于显示的电子邮件地址.然后在一个域或者控制器模版的文件里提供一个模版。
在大多数情况下,模版跟创建一个类型是一样的。ChangePasswordModel模版标签如下
image
 
创建一个新的Object.cshtml.里面用了EditorFor模版,每一个被P标签包裹。局部模版有什么好处?
首先,局部模版在视图里面都是通过名称找到的。避开在视图中明确指定哪一个模版被调用的需要,模版可以从model元数据信息中找到。此外模版能够在ViewDataDirectory中获得额外的信息,然而局部模版和其他的页面是获得不到的。这些信息在View.Data.ModelMetadata属性中.只有在ASP.NET MVC中模版才有ModelMetadata属性.在局部模版和视图,这些属性都为null
使用ModelMetadata属性时候,你能够获得从model元数据提供器生成的所有元数据信息。这些包括关于model的model类型信息,属性,和元数据。
Model类型信息包括的属性都在表3.4列出来了
image
 
除了一些model类型信息之外,ModelMetadata也包含了其他的metadata,默认的都是来自特性.如图表3.5
image
 
在我们自定义模版中,我们研究一下这些model元数据,然后去自定义HTML去呈现。除了在表3.4和3.5列出来的属性之外,ModelMetadata对象暴露了一个IDictory<string,object>类型的AdditionValues属性。这个属性包含了一些来自自定义model元数据提供者的额外的元数据信息.举个例子:如果你想展示一个必填的(required)字段,我们只需要在我们的自定义模版中检测这个IsRequired属性。比如说我们要装饰一下我们的实体中的一个DataType.DateTime数据类型的特性,我们可以用一个日期捕获插件来自定义个模版来呈现时间。
实践一下,我们可能要重写一下现有的模版,因为这个现有的Object模版可能适合,可能不适合我们的需求。这个model的元数据不能包括任何样式信息,所以自定义的样式和其他的标签都是通过重写内置的模版完成的。但是很多网站都趋向于标准的通用的用户接口布局,比如说我们通常把一个label放在一个input上面用作标记和提醒用户,或者用一个*来标记这个input是必须输入内容的。我们只需要重写模版,就可以潜移默化地影响整个站点。

比如说,我们可能希望把label放在跟input放在同一行,而不是在一列后右对齐,为了达到这个目的,我们需要重写现有的Object模版

①我们首先在 Views/Shared/下面建立一个EditorTemplates文件夹,添加一个Object.cshtml,代码如下
@foreach (var prop in ViewData.ModelMetadata.Properties
                  .Where(pm => pm.ShowForEdit
                       && !ViewData.TemplateInfo.Visited(pm)))
{ 
    <div class="editor-field-container" style="clear:both">
        @if (!String.IsNullOrEmpty(
                    Html.Label(prop.PropertyName).ToHtmlString()))
        { 
            <div class="editor-label  float-left">
                @Html.Label(prop.PropertyName)                 
            </div> 
        }
        <div class="editor-field float-left">
            @Html.Editor(prop.PropertyName)
            @Html.ValidationMessage(prop.PropertyName, "*")
        </div>
        <div class="cleaner" style="clear:both"></div>
    </div> 
  
}

②接下来修改Views/Account/Login.cshtml代码

@model GuestInfo.Models.LoginModel
 
@{
    ViewBag.Title = "登录";
}
 
<hgroup class="title">
    <h1>@ViewBag.Title.</h1>
</hgroup>
 
<section id="loginForm">
<h2>使用本地帐户登录。</h2>
@using (Html.BeginForm(new { ReturnUrl = ViewBag.ReturnUrl })) {
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)
 
    <fieldset>
        <legend>“登录”表单</legend>
        @Html.EditorForModel()
 
        <input type="submit" value="登录" />
    </fieldset>
    <p>
        @Html.ActionLink("Register", "Register") (如果你没有帐户)。
    </p>
}
</section>
 
<section class="social" id="socialLoginForm">
    <h2>使用其他服务登录。</h2>
    @Html.Action("ExternalLoginsList", new { ReturnUrl = ViewBag.ReturnUrl })
</section>
 
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

按F5运行效果,登陆页面如下:

image

我们创建了一个foreach循环,一层一层地遍历了在编辑时以前应该显示的或者不应该显示的ModelMetadata.Properties属性.展示一个label,editor模版,还有验证信息,把每一个属性放在一个div标签里面.最后我们包括了一个cleaner div重置了浮动样式应用于实现列布局.这个最终效果在图3.5
在一个全局的模版中通过放一个普通的呈现逻辑,我们可以很容易的跨站点为我们的视图,提供标准化display和editor布局.为了达需要自定义化的效果的域,我们要有选择性的重写或者提供一个新模版,通过在一个地方标准化和封装我们的呈现内容的逻辑,我们在一个地方编写了很少的代码就影响了整个站点(site),如果我们想要改变我们的时间插件,我们可以简单的写一个data-time模版,就可以很容易改变我们的站点,让它呈现不同的内容。

3.4 总结

MVC框架可以在视图(页面)里减少很多商业逻辑,不幸运的是,视图给我们带来了很多必须掌握的复杂的东西,为了应付这个复杂度和难点,为了提高视图和其他模块的结合性,我们研究了怎样使用强类型视图和隔离开的视图model,随着分离的视图model的普遍增加,使用模版从这些视图model中获得元数据来呈现内容的概念已经成为可能。在分隔开的视图model中,在你的应用程序中,我们还是要保持视图和model是分离开的理念。
 现在我们理解了视图是怎么工作的了,下一章我们将探讨一下控制器基础
 
 
第二章代码下载:http://download.csdn.net/download/yangyanghaoran/5207734

 额外赠送:

临时去除迅雷看看广告的做法【原创】
①打开资源管理器

           


②打开迅雷看看,播放任意电影,紧接着会有广告

          


    ③查看资源管理器,多了一个这个进程 XLUEOPS.exe,我们只要在广告播放的30秒内手动 关闭此进程,就可以立即 去掉广告,每次放广告,迅雷看看都会加载此进程

         

        ④右键单击它,结束进程,就可以临时去掉广告

其他方法:

    

如果你装了360安全卫士,直接点一键加速,就可以临时去掉广告



个人觉得3.3.4 自定义模版有点难,看不懂的也不用纠结我。这里只是视图基础,具体的以后再讲

关于ASP.NET MVC4 IN ACTION系列目录地址已经生成:点击查看目录

原文地址:https://www.cnblogs.com/AaronYang/p/2992649.html