ASP.NET MVC4 新手入門教程之六 ---6.編輯視圖與編輯方法

在本節中,您會爲電影控制器檢查生成的操做方法和視圖。而後,您將添加一個自定義的搜索頁面。html

運行該應用程序,而後瀏覽到Movies控制器經過將/Movies追加到您的瀏覽器的地址欄中的 URL。將鼠標指針懸停在編輯連接,看到它連接到的 URL。jquery

EditLink_sm

編輯連接是由Html.ActionLink方法在Views\Movies\Index.cshtml視圖中生成的:git

@Html.ActionLink("Edit", "Edit", new { id=item.ID }) 

Html.ActionLink

Html對象是一個幫助器,暴露使用上System.Web.Mvc.WebViewPage基類的屬性。幫助器的 ActionLink 方法,便於動態生成 HTML 超連接連接到控制器上的操做方法。ActionLink方法的第一個參數是要呈現的連接文本 (例如,<a>Edit Me</a>)。第二個參數是要調用的操做方法的名稱。最後一個參數是一個匿名對象,生成路由數據 (在本例中,ID 爲 4 的)。github

上圖中所示的生成的連接是http://localhost:xxxxx/電影/編輯/4默認的路由 (創建在App_Start\RouteConfig.cs) 採用 URL 模式{controller}/{action}/{id}所以,ASP.NET 會http://localhost:xxxxx/電影/編輯/4轉化爲對Movies 控制器參數ID等於 4 的Edit操做方法的請求。檢查App_Start\RouteConfig.cs文件中的如下代碼。web

public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); }

你也能夠經過使用查詢字符串的操做方法參數。例如,URL http://localhost:xxxxx/電影/編輯? ID = 4也向Movies控制器的Edit操做方法傳遞參數ID爲 4。ajax

EditQueryString

打開Movies控制器。兩個Edit操做方法以下所示:數據庫

// // GET: /Movies/Edit/5 public ActionResult Edit(int id = 0) { Movie movie = db.Movies.Find(id); if (movie == null) { return HttpNotFound(); } return View(movie); } // // POST: /Movies/Edit/5 [HttpPost] public ActionResult Edit(Movie movie) { if (ModelState.IsValid) { db.Entry(movie).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } return View(movie); }

通知的第二個Edit操做方法的前面 HttpPost屬性。此屬性指定,過載的Edit方法能夠調用只爲 POST 請求。你能夠將 HttpGet屬性應用於第一種編輯方法,但這是沒必要要的由於它是默認值。(咱們將引用他們做爲HttpGet方法隱式地分配HttpGet屬性的操做方法)。編程

HttpGetEdit方法獲取電影 ID 參數、 查找電影使用實體框架Find方法,並返回到編輯視圖的選定的影片。ID 參數指定默認值爲零,若是不帶參數調用該Edit 的方法。若是找不到一部電影,則會返回HttpNotFound 。當腳手架系統建立編輯視圖時,它審查Movie課並建立代碼來呈現<label><input>元素的每一個類的屬性。下面的示例演示了生成的編輯視圖:canvas

@model MvcMovie.Models.Movie

@{
    ViewBag.Title = "Edit";
}

<h2>Edit</h2> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Movie</legend> @Html.HiddenFor(model => model.ID) <div class="editor-label"> @Html.LabelFor(model => model.Title) </div> <div class="editor-field"> @Html.EditorFor(model => model.Title) @Html.ValidationMessageFor(model => model.Title) </div> <div class="editor-label"> @Html.LabelFor(model => model.ReleaseDate) </div> <div class="editor-field"> @Html.EditorFor(model => model.ReleaseDate) @Html.ValidationMessageFor(model => model.ReleaseDate) </div> <div class="editor-label"> @Html.LabelFor(model => model.Genre) </div> <div class="editor-field"> @Html.EditorFor(model => model.Genre) @Html.ValidationMessageFor(model => model.Genre) </div> <div class="editor-label"> @Html.LabelFor(model => model.Price) </div> <div class="editor-field"> @Html.EditorFor(model => model.Price) @Html.ValidationMessageFor(model => model.Price) </div> <p> <input type="submit" value="Save" /> </p> </fieldset> } <div> @Html.ActionLink("Back to List", "Index") </div> @section Scripts { @Scripts.Render("~/bundles/jqueryval") }

通知視圖模板如何將@model MvcMovie.Models.Movie語句在文件的頂部 — — 這將指定視圖預計的模型視圖模板類型Movie.api

搭建的代碼使用的幫助器方法的幾種簡化的 HTML 標記。 Html.LabelFor幫助器將顯示字段 ("標題"、"ReleaseDate"、"流派"或"價格") 的名稱。 Html.EditorFor幫手會呈現 HTML <input>元素。Html.ValidationMessageFor幫助器將顯示與該屬性相關聯的任何驗證消息。

運行該應用程序,而後定位到/Movies URL。單擊編輯連接。在瀏覽器中查看網頁的源代碼。以下所示的 HTML 表單元素。

<form action="/Movies/Edit/4" method="post"> <fieldset> <legend>Movie</legend> <input data-val="true" data-val-number="The field ID must be a number." data-val-required="The ID field is required." id="ID" name="ID" type="hidden" value="4" /> <div class="editor-label"> <label for="Title">Title</label> </div> <div class="editor-field"> <input class="text-box single-line" id="Title" name="Title" type="text" value="Rio Bravo" /> <span class="field-validation-valid" data-valmsg-for="Title" data-valmsg-replace="true"></span> </div> <div class="editor-label"> <label for="ReleaseDate">ReleaseDate</label> </div> <div class="editor-field"> <input class="text-box single-line" data-val="true" data-val-date="The field ReleaseDate must be a date." data-val-required="The ReleaseDate field is required." id="ReleaseDate" name="ReleaseDate" type="text" value="4/15/1959 12:00:00 AM" /> <span class="field-validation-valid" data-valmsg-for="ReleaseDate" data-valmsg-replace="true"></span> </div> <div class="editor-label"> <label for="Genre">Genre</label> </div> <div class="editor-field"> <input class="text-box single-line" id="Genre" name="Genre" type="text" value="Western" /> <span class="field-validation-valid" data-valmsg-for="Genre" data-valmsg-replace="true"></span> </div> <div class="editor-label"> <label for="Price">Price</label> </div> <div class="editor-field"> <input class="text-box single-line" data-val="true" data-val-number="The field Price must be a number." data-val-required="The Price field is required." id="Price" name="Price" type="text" value="2.99" /> <span class="field-validation-valid" data-valmsg-for="Price" data-valmsg-replace="true"></span> </div> <p> <input type="submit" value="Save" /> </p> </fieldset> </form>

<input>元素是其action的屬性設置爲發佈到/Movies/Edit URL HTML <form>元素。單擊編輯按鈕時,表單數據將張貼到服務器。

處理 POST 請求

下面的清單展現HttpPost版本的 Edit操做方法。

[HttpPost] public ActionResult Edit(Movie movie) { if (ModelState.IsValid) { db.Entry(movie).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } return View(movie); }

ASP.NET MVC 中的模型聯編程序取出已過賬窗體值,並建立一個Movie做爲movie參數傳遞。ModelState.IsValid方法驗證提交表單中的數據能夠用於修改 (編輯或更新)Movie對象。若是數據是有效的電影數據保存到Movies收藏的db(MovieDBContext instance)。新的電影數據將保存到數據庫中,經過調用MovieDBContext SaveChanges方法。保存數據以後, 的代碼將用戶重定向到Index操做方法的MoviesController類,顯示的電影收藏,包括剛纔所作的更改。

若是發送的值不是有效的系統會將他們從新顯示在窗體中。Edit.cshtml視圖模板Html.ValidationMessageFor傭工照顧顯示相應的錯誤消息。

abcNotValid

注意jQuery 驗證支持爲非英語區域設置,使用逗號 (",") 一個小數點,您必須包括globalize.js和你具體cultures/globalize.cultures.js文件 (從https://github.com/jquery/globalize ) 和 JavaScript 來使用 Globalize.parseFloat下面的代碼演示對要與"FR-FR"文化工做的 Views\Movies\Edit.cshtml 文件的修改:
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
    <script src="~/Scripts/globalize.js"></script> <script src="~/Scripts/globalize.culture.fr-FR.js"></script> <script> $.validator.methods.number = function (value, element) { return this.optional(element) || !isNaN(Globalize.parseFloat(value)); } $(document).ready(function () { Globalize.culture('fr-FR'); }); </script> <script> jQuery.extend(jQuery.validator.methods, { range: function (value, element, param) { //Use the Globalization plugin to parse the value  var val = $.global.parseFloat(value); return this.optional(element) || ( val >= param[0] && val <= param[1]); } }); </script> }

十進制字段可能須要一個逗號,不是小數點。做爲臨時性的措施,能夠將全球化元素添加到項目根 web.config 文件。下面的代碼顯示設置爲美國英語的文化全球化元素。

  <system.web> <globalization culture ="en-US" /> <!--elements removed for clarity--> </system.web>

全部HttpGet方法都遵循相似的模式。他們獲得電影對象 (或對象的列表,在Index的狀況下),並將模型傳遞到視圖。Create方法將空影片對象傳遞給建立視圖。建立、 編輯、 刪除或以其餘方式修改數據的方法這樣作在HttpPost重載的方法。修改 HTTP GET 方法中的數據是安全風險的博客帖子條目中所述ASP.NET MVC 提示 #46 — — 不要使用刪除連接,由於它們建立安全漏洞在 GET 方法中修改數據也違反了 HTTP 的最佳作法和建築的其餘模式,指定 GET 請求不該更改您應用程序的狀態。換句話說,執行 GET 操做,應該是沒有任何反作用,不會修改您的持久化的數據的安全操做。

添加一個搜索方法和搜索視圖

在本節中,您將添加容許您搜索電影的體裁或名稱SearchIndex操做方法。這將可以使用/Movies/SearchIndex的 URL。該請求將顯示 HTML 窗體,其中包含用戶能夠輸入要搜索的一部電影的輸入的元素。當用戶提交窗體時,該操做方法將獲取用戶張貼的搜索值和使用的值在數據庫中搜索。

顯示 SearchIndex 窗體

經過將SearchIndex操做方法添加到現有的MoviesController類開始。該方法將返回包含 HTML 窗體的視圖。下面是代碼:

public ActionResult SearchIndex(string searchString) { var movies = from m in db.Movies select m; if (!String.IsNullOrEmpty(searchString)) { movies = movies.Where(s => s.Title.Contains(searchString)); } return View(movies); }

SearchIndex方法的第一行建立如下的LINQ查詢,以選擇看電影:

var movies = from m in db.Movies select m;

查詢定義了在這一點上,但還沒有被開辦針對數據存儲區。

若是searchString參數包含一個字符串,修改電影查詢要做爲篩選依據的值的搜索字符串,使用下面的代碼:

    if (!String.IsNullOrEmpty(searchString)) { movies = movies.Where(s => s.Title.Contains(searchString)); }

s => s.Title 上面的代碼是一個Lambda 表達式Lambda 方法基於LINQ查詢中被用做在哪裏法在上面的代碼中使用標準查詢運算符方法的參數。當它們被定義或經過調用方法,如Where OrderBy被修改時,不會執行 LINQ 查詢。相反,這意味着表達式的計算延遲,直到其實現的價值實際上遍歷或ToList方法稱爲,推遲執行查詢。SearchIndex示例中,在 SearchIndex 視圖中執行查詢。有關延遲的查詢執行的詳細信息,請參閱查詢執行.

如今,您能夠實現SearchIndex認爲,將向用戶顯示窗體。SearchIndex方法內部右鍵單擊,而後單擊添加視圖添加視圖對話框中,指定要將Movie對象傳遞給視圖模板做爲其示範課。腳手架模板列表中,選擇列表,而後單擊添加.

AddSearchView

當您單擊添加按鈕時,建立Views\Movies\SearchIndex.cshtml視圖模板。由於你選擇 (就緒) 在腳手架模板列表中,Visual Studio 將自動生成的列表視圖中的某些默認標記。腳手架建立 HTML 表單。它審查Movie課,並建立代碼來呈現<label>元素的每一個類的屬性。下面的列表顯示了生成建立視圖:

@model IEnumerable<MvcMovie.Models.Movie> @{ ViewBag.Title = "SearchIndex"; } <h2>SearchIndex</h2> <p> @Html.ActionLink("Create New", "Create") </p> <table> <tr> <th> Title </th> <th> ReleaseDate </th> <th> Genre </th> <th> Price </th> <th></th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.Title) </td> <td> @Html.DisplayFor(modelItem => item.ReleaseDate) </td> <td> @Html.DisplayFor(modelItem => item.Genre) </td> <td> @Html.DisplayFor(modelItem => item.Price) </td> <td> @Html.ActionLink("Edit", "Edit", new { id=item.ID }) | @Html.ActionLink("Details", "Details", new { id=item.ID }) | @Html.ActionLink("Delete", "Delete", new { id=item.ID }) </td> </tr> } </table>

運行該應用程序,而後定位到/Movies/SearchIndex如追加查詢字符串?searchString=ghost到的 URL。將顯示篩選後的電影。

SearchQryStr

若是您更改的SearchIndex方法,有一個名爲id的參數的簽名, id參數將匹配在Global.asax文件中設置的默認路由的{id}佔位符。

{controller}/{action}/{id}

原來的SearchIndex方法看起來像這樣:

public ActionResult SearchIndex(string searchString) { var movies = from m in db.Movies select m; if (!String.IsNullOrEmpty(searchString)) { movies = movies.Where(s => s.Title.Contains(searchString)); } return View(movies); }

改進的SearchIndex方法將以下所示:

public ActionResult SearchIndex(string id) { string searchString = id; var movies = from m in db.Movies select m; if (!String.IsNullOrEmpty(searchString)) { movies = movies.Where(s => s.Title.Contains(searchString)); } return View(movies); }

如今,能夠將搜索標題做爲路由數據 (URL 段) 而不是做爲查詢字符串值傳遞。

SearchRouteData

然而,你不能期望用戶能夠修改 URL,每次他們想要尋找一部電影。因此,如今您將添加 UI,以幫助他們篩選的電影。若是您更改了SearchIndex方法來測試如何傳遞路線綁定 ID 參數的簽名,改變它回去,這樣你的SearchIndex方法採用一個名爲searchString的字符串參數:

public ActionResult SearchIndex(string searchString) { var movies = from m in db.Movies select m; if (!String.IsNullOrEmpty(searchString)) { movies = movies.Where(s => s.Title.Contains(searchString)); } return View(movies); }

打開Views\Movies\SearchIndex.cshtml文件,並只是後 @Html.ActionLink("Create New", "Create"),請添加如下內容:

@using (Html.BeginForm()){    
         <p> Title: @Html.TextBox("SearchString")<br /> <input type="submit" value="Filter" /></p> }

下面的示例顯示Views\Movies\SearchIndex.cshtml文件添加篩選標記的一部分。

@model IEnumerable<MvcMovie.Models.Movie> @{ ViewBag.Title = "SearchIndex"; } <h2>SearchIndex</h2> <p> @Html.ActionLink("Create New", "Create") @using (Html.BeginForm()){ <p> Title: @Html.TextBox("SearchString") <br /> <input type="submit" value="Filter" /></p> } </p>

Html.BeginForm幫助建立開放<form>標記。Html.BeginForm助手致使表單時用戶經過單擊篩選按鈕提交表單發送到自己。

運行應用程序並試着尋找一部電影。

還有SearchIndex方法沒有HttpPost過載。你不須要它,由於該方法不會改變應用程序的狀態只篩選數據。

您能夠添加如下HttpPost SearchIndex 方法。在這種狀況下,動做調用器將匹配HttpPost SearchIndex方法,,而且HttpPost SearchIndex方法將運行下面的圖像所示。

[HttpPost] public string SearchIndex(FormCollection fc, string searchString) { return "<h3> From [HttpPost]SearchIndex: " + searchString + "</h3>"; }

SearchPostGhost

然而,即便您添加此HttpPost 版本的 SearchIndex 方法,還有這一切如何執行的限制。想象一下你想要添加書籤特定的搜索,或你想要的連接發送給朋友他們能夠單擊以查看相同的電影已篩選的列表中。注意 HTTP POST 請求的 URL 是 GET 請求 (localhost:xxxxx/電影/SearchIndex) 的 URL 相同 — — 在 URL 自己沒有搜索信息。權利如今,搜索字符串信息發送到服務器做爲窗體字段值。這意味着你永遠不能捕捉那搜索信息,以書籤或發送給朋友在 URL 中。

解決方法是使用BeginForm ,它指定 POST 請求應添加到 URL 的搜索信息,應該把它傳遞給SearchIndex 方法的公共版本重載。現有的無參數BeginForm 方法替換爲如下內容:

@using (Html.BeginForm("SearchIndex","Movies",FormMethod.Get))

BeginFormPost_SM

如今當你提交一個搜索,該 URL 包含一個搜索查詢字符串。搜索還會去 HttpGet SearchIndex操做方法,即便你有一個 HttpPost SearchIndex方法。

SearchIndexWithGetURL

添加搜索按流派

若是您添加HttpPost版本的SearchIndex方法,當即刪除它。

接下來,您將添加一個功能,讓用戶搜索電影的體裁。SearchIndex方法替換爲如下代碼:

public ActionResult SearchIndex(string movieGenre, string searchString) { var GenreLst = new List<string>(); var GenreQry = from d in db.Movies orderby d.Genre select d.Genre; GenreLst.AddRange(GenreQry.Distinct()); ViewBag.movieGenre = new SelectList(GenreLst); var movies = from m in db.Movies select m; if (!String.IsNullOrEmpty(searchString)) { movies = movies.Where(s => s.Title.Contains(searchString)); } if (string.IsNullOrEmpty(movieGenre)) return View(movies); else { return View(movies.Where(x => x.Genre == movieGenre)); } }

此版本的SearchIndex方法須要一個額外的參數,即movieGenre第一次的幾行代碼建立一個List對象來保存電影流派從數據庫。

下面的代碼是從數據庫中檢索全部流派的 LINQ 查詢。

var GenreQry = from d in db.Movies orderby d.Genre select d.Genre;

代碼使用泛型 List集合的 AddRange方法向列表中添加全部不一樣的流派。(不帶 Distinct修飾符,將添加劇復的流派 — — 例如,喜劇會添加兩次在咱們的示例)。該代碼而後在ViewBag對象中存儲流派的列表。

下面的代碼演示如何檢查movieGenre參數。若是它不是空的該守則還限制電影查詢,以限制到指定類型的所選的電影。

 if (string.IsNullOrEmpty(movieGenre)) return View(movies); else { return View(movies.Where(x => x.Genre == movieGenre)); }

將標記添加到 SearchIndex 視圖支持按類型排列的搜索

Html.DropDownList助手添加到Views\Movies\SearchIndex.cshtml文件中,只是以前的TextBox幫手。已完成的標記以下所示:

<p> @Html.ActionLink("Create New", "Create") @using (Html.BeginForm("SearchIndex","Movies",FormMethod.Get)){ <p>Genre: @Html.DropDownList("movieGenre", "All") Title: @Html.TextBox("SearchString") <input type="submit" value="Filter" /></p> } </p>

運行該應用程序,而後瀏覽到/Movies/SearchIndex按流派、 電影的名稱,和這兩個條件,請嘗試搜索。

在本節中,您研究了 CRUD 操做方法和框架所生成的視圖。您建立了一個搜索操做方法和視圖讓用戶搜索到的電影標題和流派。在接下來的部分中,你會看看如何將一個屬性添加到Movie模型以及如何添加一個初始值設定項,將自動建立一個測試數據庫。

相關文章
相關標籤/搜索