ASP.NET MVC3书店--第五节 表单编辑(第二部分)(转)
5.5 使用HTML幫助器來截短文字
??? 使用我們的StoreManager控制器中的Index方法添加視圖的時候,有一個潛在的問題。事實上,我們的書名與作者名屬性的長度值可能超出頁面上 所定義的這兩個列的長度。我們將要專門創建一個HTML幫助器來很輕松地在頁面上截短從這兩個屬性或其他屬性中讀取出來的文字。
??? 另外,此處所講的完全是一個小的技巧,所以你如果不想使用這個技巧的話也無關緊要。學習書寫自己的HTML幫助器可以幫助簡化你的代碼書寫工作,但它不是一個必須要掌握的基礎知識。
??? 在解決方案資源管理器中追加一個名為Helpes的新的文件夾,并且在該文件夾中追加一個名為HtmlHelpers.cs的類,如圖5-4所示。
圖5-4 追加Html幫助器類及其存放的文件夾
我們的HTML幫助器將要針對ASP.NET MVC中的視圖模板中的追加一個新的”Truncate”方法。我們將要通過對ASP.NET MVC中內置的System.Web.Mvc.HtmlHelper類來實現一個“擴展方法”來實現這個處理。我們的幫助器類與方法必須聲明為static類型的。方法的書寫代碼十分簡單,如代碼清單5-6所示。
代碼清單5-6 Truncate方法的實現代碼
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方法中需要傳入兩個參數,第一個參數為需要截短的字符串,第二個參數為將字符串截短后的長度。如果字符串本身長度小于等于給定長度,方法返回該字符串本身,否則返回截短后的字符串,后面加上“…”,提示用戶該文字被截短。
??? 為了使用我們自定義的HTML幫助器,我們需要在視圖中加入對于命名空間的引用,與控制器代碼中一樣,使用using語句,追加在StoreManager控制器的Index視圖模板中的文件頭部的@model行的下面,方法如下所示。
@model IEnumerable<MvcBookStore.Models.Book>
@using MvcBookStore.Helpers
??? 現在我們可以使用我們的Html.Truncate幫助器來確保書名的長度不超過五個字符,作者名的長度不超過四個字符(僅做臨時測試用途)。使用我們新的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>
??? 現在我們可以運行應用程序,在瀏覽器中鍵入“/StoreManager/”這個URL地址,作者名與書名都被限定在指定字符串長度之下,如圖5-5所示。
圖5-5 書名與作者名都被截短
5.6 創建數據編輯視圖?
接下來,讓我們創建一個帶表單的網頁,以便網站管理員編輯書籍信息。表單中將要包括一本書的書名、單價、書籍種類等信息。稍后,我們將要追加幾個下拉框,以便管理員可以直接從中選擇作者與書籍種類信息。5.6.1?????? 實現Edit(編輯)action方法
??? 當用戶輸入“/StoreManager/Edit/[id]”這個URL地址時(id值表示要編輯書籍的ID號),StoreManager這個控制器應該實現讓管理員可以編輯書籍信息的處理。
??? 當管理員首次訪問這個地址時,我們應該運行應用程序中的有關代碼來取得數據庫中的書籍信息,然后創建一個Book對象來將這些信息以及一個作者列表、一個 種類列表進行封裝,然后將Book對象傳入一個新的視圖模板,以便向用戶顯示一個Html網頁。在這個Html網頁中將要包含一 個<form>元素,在這個表單中包括用來編輯書籍信息的文本框。
??? 管理員可以修改這個表單中的書籍信息,然后點擊保存按鈕來向應用程序提交修改后的表單值(即表單中各控件的值),并且將其保存在數據庫中。當用戶點擊保存 按鈕時,表單將會向當前的“/StoreManager/Edit/[id]”這個URL地址實行一個HTTP-POST提交,并且將表單值作為提交內容 的一部分。
??? ASP.NET MVC允許我們很輕松地將這種針對同一個URL地址的兩種調用方式(首次訪問與編輯后提交)通過在StoreManagerController控制器類中實現兩個不同的Edit方法來進行區分,一個方法用來處理首次訪問時的操作,另一個用來處理表單修改后提交時的操作。
??? 兩種不同的Edit方法的實現代碼類似如下所示。
//
// 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將會自動根據對于“/StoreManager/Edit/[id]”這個URL地址的訪問是一個HTTP-GET請求還是HTTP-POST請求來決定到底調用哪個方法。如果是一個HTTP-POST請求,則調用第二個方法,否則的話則調用第一個方法。
5.6.2??????? 書寫對于HTTP-GET請求的Edit方法
??? 通過如下所示的代碼來實現處理HTTP-GET請求的Edit方法。它從數據庫中進行書籍的查詢,然后將查詢到的數據傳入視圖模板進行顯示。
//
// GET: /StoreManager/Edit/5
public ActionResult Edit(int id)
?{
??? Book book = storeDB.Books.Find(id);
??? return View(book);
?}
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 書籍更新成功后頁面轉到書籍列表顯示頁面
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的ASP.NET MVC3书店--第五节 表单编辑(第二部分)(转)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小甲鱼Python笔记(下)
- 下一篇: GOF设计模式之1:单例设计模式