ASP.NET MVC3书店--第五节 表单编辑(第二部分)(转)
5.5 使用HTML幫助器來截短文字
??? 使用我們的StoreManager控制器中的Index方法添加視圖的時(shí)候,有一個(gè)潛在的問題。事實(shí)上,我們的書名與作者名屬性的長度值可能超出頁面上 所定義的這兩個(gè)列的長度。我們將要專門創(chuàng)建一個(gè)HTML幫助器來很輕松地在頁面上截短從這兩個(gè)屬性或其他屬性中讀取出來的文字。
??? 另外,此處所講的完全是一個(gè)小的技巧,所以你如果不想使用這個(gè)技巧的話也無關(guān)緊要。學(xué)習(xí)書寫自己的HTML幫助器可以幫助簡化你的代碼書寫工作,但它不是一個(gè)必須要掌握的基礎(chǔ)知識。
??? 在解決方案資源管理器中追加一個(gè)名為Helpes的新的文件夾,并且在該文件夾中追加一個(gè)名為HtmlHelpers.cs的類,如圖5-4所示。
圖5-4 追加Html幫助器類及其存放的文件夾
我們的HTML幫助器將要針對ASP.NET MVC中的視圖模板中的追加一個(gè)新的”Truncate”方法。我們將要通過對ASP.NET MVC中內(nèi)置的System.Web.Mvc.HtmlHelper類來實(shí)現(xiàn)一個(gè)“擴(kuò)展方法”來實(shí)現(xiàn)這個(gè)處理。我們的幫助器類與方法必須聲明為static類型的。方法的書寫代碼十分簡單,如代碼清單5-6所示。
代碼清單5-6 Truncate方法的實(shí)現(xiàn)代碼
using System.Web.Mvc;
?
namespace MvcBookStore.Helpers
{
??? public static class HtmlHelpers
??? {
??????? public static string Truncate(this HtmlHelper helper, string input,
int length)
??????? {
??????????? if (input.Length <= length)
??????????? {
??????????????? return input;
??????????? }
??????????? else
??????????? {
??????????????? return input.Substring(0, length) + "...";
??????????? }
??????? }
??? }
}
??? 在視圖代碼中需要向Truncate方法中需要傳入兩個(gè)參數(shù),第一個(gè)參數(shù)為需要截短的字符串,第二個(gè)參數(shù)為將字符串截短后的長度。如果字符串本身長度小于等于給定長度,方法返回該字符串本身,否則返回截短后的字符串,后面加上“…”,提示用戶該文字被截短。
??? 為了使用我們自定義的HTML幫助器,我們需要在視圖中加入對于命名空間的引用,與控制器代碼中一樣,使用using語句,追加在StoreManager控制器的Index視圖模板中的文件頭部的@model行的下面,方法如下所示。
@model IEnumerable<MvcBookStore.Models.Book>
@using MvcBookStore.Helpers
??? 現(xiàn)在我們可以使用我們的Html.Truncate幫助器來確保書名的長度不超過五個(gè)字符,作者名的長度不超過四個(gè)字符(僅做臨時(shí)測試用途)。使用我們新的Truncate幫助器之后的完整的視圖代碼如代碼清單5-7所示。
??? 代碼清單5-7 使用我們新的Truncate幫助器之后的完整的視圖代碼
@model IEnumerable<MvcBookStore.Models.Book>
@using MvcBookStore.Helpers
@{
??? ViewBag.Title = "書籍列表";
}
<h2>書籍列表</h2>
<p>
??? @Html.ActionLink("添加書籍", "Create")
</p>
<table>
??? <tr>
??????? <th></th>
??????? <th>書名</th>
???? ???<th>作者</th>
??????? <th>種類</th>
??? </tr>
@foreach (var item in Model) {
??? <tr>
??????? <td>
??????????? @Html.ActionLink("編輯","Edit", new { id=item.BookId }) |
??????????? @Html.ActionLink("刪除","Delete", new { id=item.BookId })
??????? </td>
??????? <td>@Html.Truncate(item.Title,5) </td>
??????? <td>@Html.Truncate(item.Author.Name,4)</td>
??????? <td>@item.Genre.Name</td>
??? </tr>
}
</table>
??? 現(xiàn)在我們可以運(yùn)行應(yīng)用程序,在瀏覽器中鍵入“/StoreManager/”這個(gè)URL地址,作者名與書名都被限定在指定字符串長度之下,如圖5-5所示。
圖5-5 書名與作者名都被截短
5.6 創(chuàng)建數(shù)據(jù)編輯視圖?
接下來,讓我們創(chuàng)建一個(gè)帶表單的網(wǎng)頁,以便網(wǎng)站管理員編輯書籍信息。表單中將要包括一本書的書名、單價(jià)、書籍種類等信息。稍后,我們將要追加幾個(gè)下拉框,以便管理員可以直接從中選擇作者與書籍種類信息。5.6.1?????? 實(shí)現(xiàn)Edit(編輯)action方法
??? 當(dāng)用戶輸入“/StoreManager/Edit/[id]”這個(gè)URL地址時(shí)(id值表示要編輯書籍的ID號),StoreManager這個(gè)控制器應(yīng)該實(shí)現(xiàn)讓管理員可以編輯書籍信息的處理。
??? 當(dāng)管理員首次訪問這個(gè)地址時(shí),我們應(yīng)該運(yùn)行應(yīng)用程序中的有關(guān)代碼來取得數(shù)據(jù)庫中的書籍信息,然后創(chuàng)建一個(gè)Book對象來將這些信息以及一個(gè)作者列表、一個(gè) 種類列表進(jìn)行封裝,然后將Book對象傳入一個(gè)新的視圖模板,以便向用戶顯示一個(gè)Html網(wǎng)頁。在這個(gè)Html網(wǎng)頁中將要包含一 個(gè)<form>元素,在這個(gè)表單中包括用來編輯書籍信息的文本框。
??? 管理員可以修改這個(gè)表單中的書籍信息,然后點(diǎn)擊保存按鈕來向應(yīng)用程序提交修改后的表單值(即表單中各控件的值),并且將其保存在數(shù)據(jù)庫中。當(dāng)用戶點(diǎn)擊保存 按鈕時(shí),表單將會向當(dāng)前的“/StoreManager/Edit/[id]”這個(gè)URL地址實(shí)行一個(gè)HTTP-POST提交,并且將表單值作為提交內(nèi)容 的一部分。
??? ASP.NET MVC允許我們很輕松地將這種針對同一個(gè)URL地址的兩種調(diào)用方式(首次訪問與編輯后提交)通過在StoreManagerController控制器類中實(shí)現(xiàn)兩個(gè)不同的Edit方法來進(jìn)行區(qū)分,一個(gè)方法用來處理首次訪問時(shí)的操作,另一個(gè)用來處理表單修改后提交時(shí)的操作。
??? 兩種不同的Edit方法的實(shí)現(xiàn)代碼類似如下所示。
//
// GET: /StoreManager/Edit/5
public ActionResult Edit(int id)
?{
??? //Display Edit form
}
//
// POST: /StoreManager/Edit/5
[HttpPost]
?public ActionResult Edit(int id, FormCollection formValues)
?{
??? //Save Book
}
??? ASP.NET MVC將會自動(dòng)根據(jù)對于“/StoreManager/Edit/[id]”這個(gè)URL地址的訪問是一個(gè)HTTP-GET請求還是HTTP-POST請求來決定到底調(diào)用哪個(gè)方法。如果是一個(gè)HTTP-POST請求,則調(diào)用第二個(gè)方法,否則的話則調(diào)用第一個(gè)方法。
5.6.2??????? 書寫對于HTTP-GET請求的Edit方法
??? 通過如下所示的代碼來實(shí)現(xiàn)處理HTTP-GET請求的Edit方法。它從數(shù)據(jù)庫中進(jìn)行書籍的查詢,然后將查詢到的數(shù)據(jù)傳入視圖模板進(jìn)行顯示。
//
// GET: /StoreManager/Edit/5
public ActionResult Edit(int id)
?{
??? Book book = storeDB.Books.Find(id);
??? return View(book);
?}
5.6.3??????? 創(chuàng)建編輯數(shù)據(jù)用視圖模板
??? 在Edit方法中點(diǎn)擊鼠標(biāo)右鍵,然后點(diǎn)擊“添加視圖”命令。在添加視圖對話框中選取“創(chuàng)建強(qiáng)類型視圖”復(fù)選框,在支架模板下拉框中選擇“Edit”(選擇編輯數(shù)據(jù)用模板),如圖5-6所示。
圖5-6 添加編輯數(shù)據(jù)用視圖
??? 點(diǎn)擊添加按鈕后,Visual Web Developer自動(dòng)創(chuàng)建的視圖中的代碼如代碼清單5-8所示(筆者已將其中文化)。
??? 代碼清單5-8 Visual Web Developer自動(dòng)創(chuàng)建的編輯數(shù)據(jù)用視圖中的代碼
@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">
?
??????? 單價(jià)
??????? </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>
??? 現(xiàn)在讓我們運(yùn)行我們的應(yīng)用程序,訪問“/StoreManager/Edit/5”這個(gè)URL地址。瀏覽器中顯示結(jié)果如圖5-7所示。
圖5-7 書籍的信息編輯頁面
5.6.4??????? 使用一個(gè)編輯器模板
??? 我們已經(jīng)看到了Visual Web Developer自動(dòng)創(chuàng)建的編輯數(shù)據(jù)用視圖中的代碼,也看到了它在瀏覽器中的運(yùn)行結(jié)果。接下來,我們通過修改這個(gè)視圖,使其使用內(nèi)置的 Html.EditorFor()幫助器方法來看一下另一種編輯數(shù)據(jù)用視圖的書寫方法。這個(gè)方法有幾個(gè)好處,包括可以將表單重用在應(yīng)用程序的其他視圖中。
??? 將我們的編輯數(shù)據(jù)用視圖中的代碼修改為如代碼清單5-9中所示的代碼(筆者已對其進(jìn)行過中文化處理)。
??? 代碼清單5-9 另一種編輯數(shù)據(jù)用視圖的代碼書寫方法
@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>
??? 再次重新運(yùn)行應(yīng)用程序并訪問“/StoreManager/Edit/5”這個(gè)URL地址,瀏覽器中所示結(jié)果如圖5-8所示(默認(rèn)的編輯模板中為直接顯示模型的屬性名,稍后介紹如何修改成中文)。
圖5-8 第二種方法創(chuàng)建的編輯數(shù)據(jù)用視圖的顯示結(jié)果
??? 我們已經(jīng)介紹了創(chuàng)建編輯數(shù)據(jù)用視圖的兩種方法:
??? 1) 我們可以使用添加數(shù)據(jù)對話框來為模型中的所有屬性添加編輯控件,而這些編輯控件的代碼全部被書寫在Edit.cshtml視圖模板文件中。
??? 2) 我們也可以使用ASP.NET MVC中的模板來書寫視圖,編輯控件的代碼全部被封裝在模板中,瀏覽器通過運(yùn)行時(shí)解析模板來顯示表單及其控件。
這兩種方法在不同的情況下各有各的優(yōu)勢。接下來,我們繼續(xù)使用Html.EditForModel()這個(gè)模板特性,以便可以在一個(gè)視圖中引用其他視圖。
5.6.5????????? 創(chuàng)建一個(gè)公共的書籍編輯器模板
??? 我們的書籍編輯視圖與書籍添加視圖中的表單中的內(nèi)容是完全一致的,所以我們可以使用一個(gè)公共的書籍編輯器模板。在我們的應(yīng)用程序中多處重用一個(gè)編輯器模板可以給用戶一種操作連貫的感覺。同樣也由于不用在多處復(fù)制同一段代碼而提高了代碼的可管理性與可維護(hù)性。
?? ?ASP.NET MVC遵循一種對于模板訪問方法的默認(rèn)約定,所以文件夾與文件名是十分重要的。當(dāng)我們在視圖模板中使用Html.EditorForModel()方法 時(shí),MVC在運(yùn)行的時(shí)候也會在Views文件夾下的EditorTemplates文件夾中尋找名字與模型名相同的模板文件,如果找到則使用它來進(jìn)行視圖 的顯示。這意味著我們可以通過修改該模板文件中的代碼來定制任何類型的模型的頁面顯示結(jié)果。
?? 接下來,我們在Views文件夾下的Shared文件夾中添加一個(gè)EditorTemplates文件夾,然后追加一個(gè)新的視圖模板,如圖5-9所示。
圖5-9 在EditorTemplates文件夾中追加視圖模板
??? 這個(gè)視圖與我們之前所創(chuàng)建的視圖略有不同。它是一個(gè)分部視圖,表示它的用途是用來被引用在其他視圖中。在添加視圖對話框中,將視圖命名為Book,在視圖模板下拉框中選擇“Edit”,選取“創(chuàng)建分部視圖復(fù)選框”然后點(diǎn)擊追加按鈕,如圖5-10所示。
圖5-10 添加分部視圖
點(diǎn)擊添加按鈕,然后查看Visual Web Developer中自動(dòng)創(chuàng)建的該視圖文件(Book.cshtml文件)的代碼,該文件中被默認(rèn)追加了一個(gè)form標(biāo)簽,但是由于我們在其他視圖中引用這個(gè)視圖,而其他視圖中已經(jīng)追加了form標(biāo)簽,所以我們可以刪除此處的form標(biāo)簽。代碼如代碼清單5-10所示(筆者已對其進(jìn)行中文化處理)。
 ??? 代碼清單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">
單價(jià)
</div>
<div class="editor-field">
??? @Html.EditorFor(model =>model.Price)
??? @Html.ValidationMessageFor(model=> model.Price)
?</div>
??? 運(yùn)行應(yīng)用程序,并且訪問“/StoreManager/Edit/5”這個(gè)URL地址,可以看出我們在頁面中使用了編輯書籍用表單,而書籍ID編號再次被隱藏起來,如圖5-11所示。
?
圖5-11 編輯模板的顯示結(jié)果
??? 接下來,讓我們來看一下如何修改這個(gè)編輯書籍信息時(shí)所用的編輯模板。
5.6.6??????? 使用ViewBag來將附加信息傳入視圖
??? 接下來,讓我們對這個(gè)編輯模板中的表單做出局部修改,使用下拉框來進(jìn)行書籍與書籍種類的顯示,而不是使用文本框來進(jìn)行顯示。為了能看出效果,需要向我們的視圖中傳入一些對象及其所帶數(shù)據(jù)。此處,它需要如下對象:
??? 1) 一個(gè)代表當(dāng)前需要被編輯的書籍的Book對象
??? 2) 一個(gè)代表所有書籍種類的Genres對象列表,我們使用這個(gè)列表來設(shè)置書籍種類下拉框中的內(nèi)容。
??? 3) 一個(gè)代表所有作者的Authors對象列表,我們使用這個(gè)列表來設(shè)置作者下拉框中的內(nèi)容。
通過使用ViewBag對象,控制器可以來將這兩個(gè)代表所有種類的種類列表與代表所有書籍的書籍列表傳入視圖中。
因此,我們將StoreManager控制器類中的Edit方法(第一個(gè))中的代碼修改為如下所示的代碼。
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);
?}
??? 現(xiàn)在,我們的控制器已經(jīng)將一本書的信息作為模型對象傳入了編輯視圖中,編輯視圖使用編輯模板來顯示這本書的信息。同時(shí)也將編輯模板中的書籍下拉框與書籍種 類下拉框中所需內(nèi)容通過ViewBag對象傳入了編輯模板中。現(xiàn)在,我們準(zhǔn)備在作者編輯模板中寫入書籍下拉框與書籍種類下拉框的頁面代碼。
5.6.7??????? 在書籍編輯模板中使用下拉框
??? 我們將使用HTML幫助器—Html.DropDownList來創(chuàng)建我們的下拉框。首先讓我們來看一下需要向幫助器中傳入什么參數(shù)。
- 模型中的屬性名(AuthorId)
- 下拉框中的內(nèi)容,使用SelectList對象來進(jìn)行設(shè)置
- 用模型中的什么屬性來設(shè)置每一個(gè)下拉框選項(xiàng)的value值時(shí),需要傳入該屬性名,提交時(shí)用該屬性來代表下拉框選項(xiàng)的value值
- 用模型中的什么屬性來設(shè)置每一個(gè)下拉框選項(xiàng)的頁面顯示文字,需要傳入該屬性名
- 用模型中的什么屬性來設(shè)置顯示表單時(shí)下拉框的當(dāng)前被選中的選項(xiàng)的value值,需要傳入該屬性名
??? 調(diào)用Html.DropDownList幫助器的方法時(shí)所寫代碼類似如下所示。
@Html.DropDownList("AuthorId",new SelectList(ViewBag.Artists as
System.Collections.IEnumerable,"AuthorId", "Name", Model.AuthorId))
??? 現(xiàn)在我們的完整的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>
??? 單價(jià)
??? @Html.TextBoxFor(model =>model.Price)
??? @Html.ValidationMessageFor(model=> model.Price)
</p>
??? 現(xiàn)在我們可以通過StoreManager控制器來編輯書籍信息,而頁面中的作者與種類文本框也被下拉框所代替,如圖5-12所示。
圖5-12 使用下拉框的編輯模板
5.6.8??????? 實(shí)現(xiàn)處理HTTP-POST請求的Edit方法
??? 接下來,我們來看一下第二個(gè)場景,當(dāng)管理員點(diǎn)擊保存按鈕,將表單值使用HTTP-POST請求提交給服務(wù)器,要求將這些值保存到數(shù)據(jù)庫中。我們需要使用另外Edit方法,該方法使用一個(gè)ID參數(shù)與一個(gè)FormCollection對象參數(shù)(從HTML FORM讀取)。我們使用“HttpPost”屬性來對這個(gè)方法進(jìn)行注解,標(biāo)示該方法被調(diào)用在對于“/StoreManager/Edit/[id]”這個(gè)URL地址進(jìn)行HTTP-POST的時(shí)候。
??? 該方法中將要執(zhí)行如下三步處理:
??? 1.根據(jù)傳入的ID編號讀取數(shù)據(jù)庫中該書籍的信息。
??? 2.嘗試使用客戶端提交上來的表單值來對書籍進(jìn)行更新操作,使用控制器中內(nèi)置的UpdateModel方法。
??? 3.將執(zhí)行結(jié)果返回給用戶,包括更新出錯(cuò)時(shí)重新顯示編輯表單,或者更新成功后將頁面轉(zhuǎn)到書籍列表頁面。
??? 該方法中的代碼如下所示。
//
// 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”屬性,表示該方法只被調(diào)用在客戶端發(fā)出HTTP-POST請求的時(shí)候。
??? 現(xiàn)在我們可以對書籍進(jìn)行編輯了。運(yùn)行應(yīng)用程序,輸入“/StoreManager/Edit/5”這個(gè)URL地址,然后修改該書籍信息,如圖5-13所示。
圖5-13 修改書籍信息
??? 修改完成后點(diǎn)擊保存按鈕,服務(wù)器端對該書籍進(jìn)行更新,成功后頁面轉(zhuǎn)到書籍列表顯示頁面,如圖5-14所示。
圖5-14 書籍更新成功后頁面轉(zhuǎn)到書籍列表顯示頁面
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的ASP.NET MVC3书店--第五节 表单编辑(第二部分)(转)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 小甲鱼Python笔记(下)
- 下一篇: linux 流场分析软件,scSTREA
