}
5.6.3 创建编辑数据用视图模板
在Edit方法中点击鼠标右键,然后点击“添加视图”命令。在添加视图对话框中选取“创建强类型视图”复选框,在支架模板下拉框中选择“Edit”(选择编辑数据用模板),如图5-6所示。

图5-6 添加编辑数据用视图
点击添加按钮后,Visual Web Developer自动创建的视图中的代码如代码清单5-8所示(笔者已将其中文化)。
代码清单5-8 Visual Web Developer自动创建的编辑数据用视图中的代码
@model MvcBookStore.Models.Book
@{
ViewBag.Title = "编辑书籍";
}
<h2>编辑书籍</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")"
type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"
type="text/javascript"></script>
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>书籍信息</legend>
@Html.HiddenFor(model =>model.BookId)
<div class="editor-label">
书籍种类
</div>
<div class="editor-field">
@Html.EditorFor(model =>model.GenreId)
@Html.ValidationMessageFor(model=> model.GenreId)
</div>
<div class="editor-label">
作者编号
</div>
<div class="editor-field">
@Html.EditorFor(model =>model.AuthorId)
@Html.ValidationMessageFor(model=> model.AuthorId)
</div>
<div class="editor-label">
书名
</div>
<div class="editor-field">
@Html.EditorFor(model =>model.Title)
@Html.ValidationMessageFor(model=> model.Title)
</div>
<div class="editor-label">
单价
</div>
<div class="editor-field">
@Html.EditorFor(model =>model.Price)
@Html.ValidationMessageFor(model=> model.Price)
</div>
<p>
<input type="submit" value="保存" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("返回书籍列表", "Index")
</div>
现在让我们运行我们的应用程序,访问“/StoreManager/Edit/5”这个URL地址。浏览器中显示结果如图5-7所示。

图5-7 书籍的信息编辑页面
5.6.4 使用一个编辑器模板
我们已经看到了Visual Web Developer自动创建的编辑数据用视图中的代码,也看到了它在浏览器中的运行结果。接下来,我们通过修改这个视图,使其使用内置的 Html.EditorFor()帮助器方法来看一下另一种编辑数据用视图的书写方法。这个方法有几个好处,包括可以将表单重用在应用程序的其他视图中。
将我们的编辑数据用视图中的代码修改为如代码清单5-9中所示的代码(笔者已对其进行过中文化处理)。
代码清单5-9 另一种编辑数据用视图的代码书写方法
@model MvcBookStore.Models.Book
@{
ViewBag.Title = "编辑 - " + Model.Title;
}
<h2>编辑书籍</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")"
type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"
type="text/javascript"></script>
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>编辑书籍</legend>
@Html.EditorForModel()
<p>
<input type="submit" value="保存" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("返回书籍列表", "Index")
</div>
再次重新运行应用程序并访问“/StoreManager/Edit/5”这个URL地址,浏览器中所示结果如图5-8所示(默认的编辑模板中为直接显示模型的属性名,稍后介绍如何修改成中文)。

图5-8 第二种方法创建的编辑数据用视图的显示结果
我们已经介绍了创建编辑数据用视图的两种方法:
1) 我们可以使用添加数据对话框来为模型中的所有属性添加编辑控件,而这些编辑控件的代码全部被书写在Edit.cshtml视图模板文件中。
2) 我们也可以使用ASP.NET MVC中的模板来书写视图,编辑控件的代码全部被封装在模板中,浏览器通过运行时解析模板来显示表单及其控件。
这两种方法在不同的情况下各有各的优势。接下来,我们继续使用Html.EditForModel()这个模板特性,以便可以在一个视图中引用其他视图。
5.6.5 创建一个公共的书籍编辑器模板
我们的书籍编辑视图与书籍添加视图中的表单中的内容是完全一致的,所以我们可以使用一个公共的书籍编辑器模板。在我们的应用程序中多处重用一个编辑器模板可以给用户一种操作连贯的感觉。同样也由于不用在多处复制同一段代码而提高了代码的可管理性与可维护性。
ASP.NET MVC遵循一种对于模板访问方法的默认约定,所以文件夹与文件名是十分重要的。当我们在视图模板中使用Html.EditorForModel()方法 时,MVC在运行的时候也会在Views文件夹下的EditorTemplates文件夹中寻找名字与模型名相同的模板文件,如果找到则使用它来进行视图 的显示。这意味着我们可以通过修改该模板文件中的代码来定制任何类型的模型的页面显示结果。
接下来,我们在Views文件夹下的Shared文件夹中添加一个EditorTemplates文件夹,然后追加一个新的视图模板,如图5-9所示。

图5-9 在EditorTemplates文件夹中追加视图模板
这个视图与我们之前所创建的视图略有不同。它是一个分部视图,表示它的用途是用来被引用在其他视图中。在添加视图对话框中,将视图命名为Book,在视图模板下拉框中选择“Edit”,选取“创建分部视图复选框”然后点击追加按钮,如图5-10所示。

图5-10 添加分部视图
点击添加按钮,然后查看Visual Web Developer中自动创建的该视图文件(Book.cshtml文件)的代码,该文件中被默认追加了一个form标签,但是由于我们在其他视图中引用这个视图,而其他视图中已经追加了form标签,所以我们可以删除此处的form标签。代码如代码清单5-10所示(笔者已对其进行中文化处理)。
代码清单5-10 在EditorTemplates文件夹中追加的编辑模板中的代码
@model MvcBookStore.Models.Book
@Html.HiddenFor(model => model.Id)
<div class="editor-label">
种类编号
</div>
<div class="editor-field">
@Html.EditorFor(model =>model.GenreId)
@Html.ValidationMessageFor(model=> model.GenreId)
</div>
<div class="editor-label">
作者编号
</div>
<div class="editor-field">
@Html.EditorFor(model =>model.AuthorId)
@Html.ValidationMessageFor(model=> model.AuthorId)
</div>
<div class="editor-label">
书名
</div>
<div class="editor-field">
@Html.EditorFor(model =>model.Title)
@Html.ValidationMessageFor(model=> model.Title)
</div>
<div class="editor-label">
单价
</div>
<div class="editor-field">
@Html.EditorFor(model =>model.Price)
@Html.ValidationMessageFor(model=> model.Price)
</div>
运行应用程序,并且访问“/StoreManager/Edit/5”这个URL地址,可以看出我们在页面中使用了编辑书籍用表单,而书籍ID编号再次被隐藏起来,如图5-11所示。

图5-11 编辑模板的显示结果
接下来,让我们来看一下如何修改这个编辑书籍信息时所用的编辑模板。
5.6.6 使用ViewBag来将附加信息传入视图
接下来,让我们对这个编辑模板中的表单做出局部修改,使用下拉框来进行书籍与书籍种类的显示,而不是使用文本框来进行显示。为了能看出效果,需要向我们的视图中传入一些对象及其所带数据。此处,它需要如下对象:
1) 一个代表当前需要被编辑的书籍的Book对象
2) 一个代表所有书籍种类的Genres对象列表,我们使用这个列表来设置书籍种类下拉框中的内容。
3) 一个代表所有作者的Authors对象列表,我们使用这个列表来设置作者下拉框中的内容。
通过使用ViewBag对象,控制器可以来将这两个代表所有种类的种类列表与代表所有书籍的书籍列表传入视图中。
因此,我们将StoreManager控制器类中的Edit方法(第一个)中的代码修改为如下所示的代码。
public ActionResult Edit(int id)
{
ViewBag.Genres = storeDB.Genres.OrderBy(g=> g.Name).ToList();
ViewBag.Authors = storeDB.Authors.OrderBy(a => a.Name).ToList();
var book = storeDB.Books.Single(a => a.Id == id);
return View(book);
}
现在,我们的控制器已经将一本书的信息作为模型对象传入了编辑视图中,编辑视图使用编辑模板来显示这本书的信息。同时也将编辑模板中的书籍下拉框与书籍种 类下拉框中所需内容通过ViewBag对象传入了编辑模板中。现在,我们准备在作者编辑模板中写入书籍下拉框与书籍种类下拉框的页面代码。
5.6.7 在书籍编辑模板中使用下拉框
我们将使用HTML帮助器—Html.DropDownList来创建我们的下拉框。首先让我们来看一下需要向帮助器中传入什么参数。
- 模型中的属性名(AuthorId)
- 下拉框中的内容,使用SelectList对象来进行设置
- 用模型中的什么属性来设置每一个下拉框选项的value值时,需要传入该属性名,提交时用该属性来代表下拉框选项的value值
- 用模型中的什么属性来设置每一个下拉框选项的页面显示文字,需要传入该属性名
- 用模型中的什么属性来设置显示表单时下拉框的当前被选中的选项的value值,需要传入该属性名
调用Html.DropDownList帮助器的方法时所写代码类似如下所示。
@Html.DropDownList("AuthorId",new SelectList(ViewBag.Artists as
System.Collections.IEnumerable,"AuthorId", "Name", Model.AuthorId))
现在我们的完整的Book.cshtml编辑模板中的代码如代码清单5-11所示(笔者已做中文化处理)。
代码清单5-11 完整的Book.cshtml编辑模板中的代码
@model MvcBookStore.Models.Book
<p>
书籍种类
@Html.DropDownList("GenreId",new SelectList(ViewBag.Genres as
System.Collections.IEnumerable,"GenreId", "Name", Model.GenreId))
</p>
<p>
作者
@Html.DropDownList("AuthorId",new SelectList(ViewBag.Authors as
System.Collections.IEnumerable,"AuthorId", "Name", Model.AuthorId))
</p>
<p>
书名
@Html.TextBoxFor(model =>model.Title)
@Html.ValidationMessageFor(model=> model.Title)
</p>
<p>
单价
@Html.TextBoxFor(model =>model.Price)
@Html.ValidationMessageFor(model=> model.Price)
</p>
现在我们可以通过StoreManager控制器来编辑书籍信息,而页面中的作者与种类文本框也被下拉框所代替,如图5-12所示。

图5-12 使用下拉框的编辑模板
5.6.8 实现处理HTTP-POST请求的Edit方法
接下来,我们来看一下第二个场景,当管理员点击保存按钮,将表单值使用HTTP-POST请求提交给服务器,要求将这些值保存到数据库中。我们需要使用另外Edit方法,该方法使用一个ID参数与一个FormCollection对象参数(从HTML FORM读取)。我们使用“HttpPost”属性来对这个方法进行注解,标示该方法被调用在对于“/StoreManager/Edit/[id]”这个URL地址进行HTTP-POST的时候。
该方法中将要执行如下三步处理:
1.根据传入的ID编号读取数据库中该书籍的信息。
2.尝试使用客户端提交上来的表单值来对书籍进行更新操作,使用控制器中内置的UpdateModel方法。
3.将执行结果返回给用户,包括更新出错时重新显示编辑表单,或者更新成功后将页面转到书籍列表页面。
该方法中的代码如下所示。
//
// POST: /StoreManager/Edit/5
[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
var book = storeDB.Books.Find(id);
if(TryUpdateModel(book))
{
storeDB.SaveChanges();
return RedirectToAction("Index");
}
else
{
ViewBag.Genres = storeDB.Genres.OrderBy(g => g.Name).ToList();
ViewBag.Authors = storeDB.Authors.OrderBy(a => a.Name).ToList();
return View(book);
}
}
我们使用了“HttpPost”属性,表示该方法只被调用在客户端发出HTTP-POST请求的时候。
现在我们可以对书籍进行编辑了。运行应用程序,输入“/StoreManager/Edit/5”这个URL地址,然后修改该书籍信息,如图5-13所示。

图5-13 修改书籍信息
修改完成后点击保存按钮,服务器端对该书籍进行更新,成功后页面转到书籍列表显示页面,如图5-14所示。

图5-14 书籍更新成功后页面转到书籍列表显示页面