边看边译《asp.net mvc 4 in action》(二)

3.2.3 带视图模型的强类型视图

当使用基于Razor的视图时,视图默认继承两个类型:System.Web.Mvc.WebViewPage或者System.Web.Mvc.WebViewPage<T>。泛型WebViewPage<T>继承自WebViewPage,但是提供了一些非泛型WebViewPage类里没有的独特的补充。

      下面展示了WebViewPage<T>的主干成员定义:

 

清单 3.3

 

public class WebViewPage<TModel> : WebViewPage
{
public new AjaxHelper<TModel> Ajax { getset; }
public new HtmlHelper<TModel> Html { getset; }
public new TModel Model { get; }
public new ViewDataDictionary<TModel> ViewData { getset; }
}

 

除了通过Model属性在ViewData.Model之上提供了一个强类型包装器外,WebViewPage<T>类还提供访问关联视图的帮助器对象的强类型版本,AjaxHelper和HtmlHelper。

     要使用强类型视图,首先你必须确保控制器动作正确设置了ViewData.Model。在清单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关键词指定模型的类型。

 

@using Guestbook.Models
@model List<GuestbookEntry>

通过用@model关键词指定模型的类型,我们的视图现在继承自WebViewPage<T>而不是WebViewPage,我们有了一个强类型视图。我们也用@using关键词导入名字空间。在下一部分,我们将看到如何使用模型对象在视图里显示信息。

 

3.2.4

一般要在视图里显示信息,你可以使用HtmlHelper对象帮助获得视图模型以生成HTML。考虑下下面的清单,我们呈现了一个完整的留言板记录。

清单 3.5

 

<h2>Guestbook Entry</h2>
<dl>
<dt>Name:</dt>
<dd>@Model.Name</dd>
<dt>Date 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>

在这里,我们显示在模型里传递的留言板详细信息。接着,我们用Razor多行代码语句从ViewData中获取”hasPermission“的值。Razor多行语句用at符号后跟一个大括号来开始一个代码块:@{。最后,我们用一个Razor的if块来有条件的显示Edit链接。因为当在屏幕上显示未编码的用户输入时有可能遭到各种脚本攻击,所以数据在呈现到屏幕以前默认是被自动编码的。为了显示未编码的信息,我们可以使用Html.Raw方法强制显示原生文本。

      在登录页面,我们用一个视图模型对象代表完整的表单,就像下面清单显示的:

清单 3.6

 

public class LogOnModel
{
[Required]
[Display(Name = "User name")]
public string UserName { getset; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { getset; }
[Display(Name = "Remember me?")]
public bool RememberMe { getset; }
}

LogOnModel类很简单,只包括必须的属性。你在这里看到的特性是数据注解,关于它们更多的内容会在第4章学到。对于每一个属性在登录页面都会显示一个输入元素,如图3.2所示。

图3.2 登录页

 

因为我们为登陆页选择了强类型视图,我们能用内建的帮助器来为每一个输入元素绘制出HTML。取代松散的绑定到代表动作参数的字符串,我们能利用基于表达式的HtmlHelper扩展创建各种类型的输入元素,如下:

清单 3.7

 

@using (Html.BeginForm()) {
@Html.ValidationSummary(true,
"Account creation was unsuccessful. " +
"Please correct the errors and try again.")
<div>
<fieldset>
<legend>Account Information</legend>
<div class="editor-label">
@Html.LabelFor(m => m.UserName)
</div>
<div class="editor-field">
@Html.TextBoxFor(m => m.UserName)
@Html.ValidationMessageFor(
m => m.UserName)
</div>
<div class="editor-label">
@Html.LabelFor(m => m.Email)
</div>
<div class="editor-field">
@Html.TextBoxFor(m => m.Email)
@Html.ValidationMessageFor(m => m.Email)
</div>
<div class="editor-label">
@Html.LabelFor(m => m.Password)
</div>
<div class="editor-field">
@Html.PasswordFor(m => m.Password)
@Html.ValidationMessageFor(m => m.Password)
</div>
<div class="editor-label">
@Html.LabelFor(m => m.ConfirmPassword)
</div>
<div class="editor-field">
@Html.PasswordFor(m => m.ConfirmPassword)
@Html.ValidationMessageFor(m => m.ConfirmPassword)
</div>
<p>
<input type="submit" value="Register" />
</p>
</fieldset>
</div>
}

在先前的清单里,我们为强类型视图页面使用了几个HtmlHelper的扩展方法,这些方法分别针对标签,输入框和验证信息。取代用松散类型的字符串代表属性,在asp.net mvc 1里就是这样使用( @Html.TextBox("UserName")),这些帮助器方法利用c# 3.5的表达式来生成HTML。因为这些生成的HTML元素需要与对象中的属性匹配,所以只适合用于原生的类型和与表达式一起使用的对象。

     在清单3.7里Html.LabelFor和Html.TextBoxFor方法为UserNam属性产生HTML:

清单3.8

<label for="UserName">User name</label>
<input id="UserName" name="UserName" type="text" value="" />

为了让我们的页面通过可访问性验证,每一个输入元素(如清单3.8的第二行)需要包含一个相应的标签元素(如第一行)。因为我们的标签和输入元素都是用表达式生成的,所以我们不再担心标签和输入名称硬编码的问题。

      表格3.1列出了用于强类型视图的HtmlHelper的各种扩展方法。

 

表格3.1

  •  DisplayFor
  • DisplayTextFor
  • EditorFor
  • CheckBoxFor
  • DropDownListFor
  • HiddenFor
  • LabelFor
  • ListBoxFor
  • PasswordFor
  • RadioButtonFor
  • TextAreaFor
  • TextBoxFor
  • ValidateFor
  • ValidationMessageFor

由于我们的表单是用强类型视图生成的,我们可以在设计表单post的动作上利用这一点。不用枚举每个输入域的值作为动作方法的参数,我们可以把所有的参数都绑定到与呈现视图同一个的视图模型上,如下所示。

清单3.9

 

public ActionResult LogOn(LogOnModel model, string returnUrl)
{
// Action method body here
...
}

正如你看见的,LogOn动作方法使用单个LogOnModel对象,以及要返回的URL,而不是为表单里的每个输入元素用一个方法参数。

     HtmlHelper扩展可能是强大的,但如果只依赖这些扩展产生HTML,在视图里仍然会引入了相当多的重复。例如,如果每个输入元素需要一个相应的标签,为什么不总是包括它呢?每个用户界面是不同的,所以MVC团队不能预知每个人所用的输入和标签元素的布局。虽然每个输入元素都应该有一个标签,现有的创建输入元素的辅助方法不适合包括标签元素。作为替代方案,我们可以利用在asp.net mvc 2里介绍的功能——模版——用一种标准化的方式产生HTML。

posted @ 2012-06-25 23:15  qlbc  阅读(1921)  评论(6编辑  收藏  举报