天天看點

C# MVC 自學筆記—6 編輯方法和編輯視圖

==============================翻譯==============================

運作該應用程式并浏覽到

Movies

控制器通過将/Movies追加到您的浏覽器的位址欄中的 URL。将滑鼠指針懸停在編輯連結,看到它連結到的 URL。

C# MVC 自學筆記—6 編輯方法和編輯視圖

編輯連結是由Views\Movies\Index.cshtml視圖中的

Html.ActionLink

方法生成的:

@Html.ActionLink("Edit", "Edit", new { id=item.ID })       
C# MVC 自學筆記—6 編輯方法和編輯視圖

Html

對象是一個幫助器,公開使用System.Web.Mvc.WebViewPage基類的類上的屬性。利用幫助程式的

ActionLink

方法,可以很容易地動态生成相應的 HTML 超連結,以連結到控制器上的操作方法。

ActionLink

方法的第一個參數是要呈現的連結文本 (例如,

<a>Edit Me</a>

)。第二個參數是要調用的操作方法的名稱。最後一個參數是資料生成的路由 (在本例中,ID 為 4 的) 中的匿名對象。

上圖中所示的生成的連結是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檔案中的以下代碼。

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 }
    );
}      

您還可以傳遞使用查詢字元串的操作方法參數。例如,URLhttp://localhost:xxxxx/電影/編輯? ID = 4還将參數

ID

為 4 的傳遞給

Edit

Movies

控制器的操作方法。

C# MVC 自學筆記—6 編輯方法和編輯視圖

打開

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

屬性的操作方法。

HttpGet

Edit

方法擷取電影 ID 參數、 查找電影使用實體架構

Find

方法,并傳回到編輯視圖的標明的影片。ID 參數指定預設值為零,如果不帶參數調用該

Edit

的方法。如果不能找到一部電影,則傳回HttpNotFound。當腳手架系統建立的編輯視圖時,它審查

Movie

類并建立呈現

<label>

<input>

元素的每個屬性的類的代碼。下面的示例顯示了編輯視圖生成的:

@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

類型.

基架的代碼使用的幫助器方法的幾種簡化的 HTML 标記。

Html.LabelFor

helper 顯示字段 ("标題"、"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/EditURL 的 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)。通過調用

SaveChanges

方法

MovieDBContext

的情況下,新的電影資料儲存到資料庫。儲存資料之後,代碼把使用者重定向到的

MoviesController

類,其中顯示了

Index

操作方法的電影收藏,包括剛才所做的更改。

如果發送的值不是有效的系統會将他們重新顯示在窗體中。Edit.cshtml視圖模闆中的

Html.ValidationMessageFor

傭工照顧顯示相應的錯誤消息。

C# MVC 自學筆記—6 編輯方法和編輯視圖

注意要支援 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 表達式。例如,其中的方法在上面的代碼中使用标準查詢運算符方法的參數的方法基于LINQ查詢使用,lambda。當他們被定義或被修改的調用 (如

Where

OrderBy

方法時不執行 LINQ 查詢。相反,延遲查詢執行,這意味着表達式的計算延遲,直到其實作的價值實際上來反複或

ToList

方法調用。在

SearchIndex

示例中,SearchIndex 視圖中執行查詢。有關延遲的查詢執行的詳細資訊,請參閱查詢執行.

現在,您可以實作

SearchIndex

視圖,以便向使用者顯示該窗體。在

SearchIndex

方法内右鍵單擊,然後單擊添加視圖。在添加視圖對話框中,指定您要将

Movie

對象傳遞到視圖模闆作為其模型類。在基架模闆清單中,選擇清單,然後單擊添加.

C# MVC 自學筆記—6 編輯方法和編輯視圖

當您單擊添加按鈕時,建立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。顯示已篩選的電影。

C# MVC 自學筆記—6 編輯方法和編輯視圖

如果您更改的

SearchIndex

方法,有一個名為

id

參數的簽名,

id

參數将比對

{id}

占位符在Global.asax檔案中設定的預設路由。

{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 部分) 而不是作為查詢字元串值傳遞。

C# MVC 自學筆記—6 編輯方法和編輯視圖

但是,你不能指望使用者修改 URL,每次他們想要搜尋的一部電影。是以,現在您将添加使用者界面,幫助他們篩選的電影。如果您更改了的

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

幫助器将導緻窗體張貼到其本身。

運作該應用程式并試着尋找一部電影。

C# MVC 自學筆記—6 編輯方法和編輯視圖

沒有任何

HttpPost

重載的

SearchIndex

方法。你不需要它,因為該方法不更改狀态的應用程式,隻篩選資料。

您可以添加以下

HttpPost SearchIndex

方法。在這種情況下,操作調用程式将比對

HttpPost SearchIndex

方法,并且

HttpPost SearchIndex

方法将運作,如下圖所示。

[HttpPost] 
public string SearchIndex(FormCollection fc, string searchString) 
{ 
    return "<h3> From [HttpPost]SearchIndex: " + searchString + "</h3>"; 
}      
C# MVC 自學筆記—6 編輯方法和編輯視圖

但是,即使您添加此

HttpPost

版本的

SearchIndex

方法,有這一切如何執行的限制。想象一下你想要添加書簽特定的搜尋或你想要的連結發送給朋友他們可以單擊看看同一篩選清單中的電影。請注意 HTTP POST 請求的 URL 是 GET 請求 (localhost:xxxxx/電影/SearchIndex) 的 URL 相同 — — 在 URL 本身沒有搜尋資訊。現在,搜尋字元串資訊作為窗體字段值發送到伺服器。這意味着您不能捕獲該搜尋資訊以建立書簽或在 URL 中發送給朋友。

解決方案是使用

BeginForm

,它指定 POST 請求應添加到 URL 的搜尋資訊和它應該被路由到公共版本的

SearchIndex

方法的重載。現有無參數

BeginForm

方法替換為以下内容:

@using (Html.BeginForm("SearchIndex","Movies",FormMethod.Get))      
C# MVC 自學筆記—6 編輯方法和編輯視圖

現在當您送出一個搜尋,該 URL 包含一個搜尋的查詢字元串。搜尋還會去

HttpGet SearchIndex

操作方法,即使你有

HttpPost SearchIndex

的一種方法。

C# MVC 自學筆記—6 編輯方法和編輯視圖

添加搜尋按流派

如果您添加

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 視圖,支援按類型排列的主題搜尋

添加到Views\Movies\SearchIndex.cshtml檔案中,隻是之前在

TextBox

傭工

Html.DropDownList

幫助器。已完成的标記如下所示:

<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。按流派、 按電影名稱,和由這兩個條件,請嘗試搜尋。

C# MVC 自學筆記—6 編輯方法和編輯視圖

在這一節中您審查的 CRUD 操作方法和架構所生成的視圖。您建立了一個搜尋操作方法和視圖,讓使用者搜尋的電影标題和流派。在下一節中,你就會看看如何将一個屬性添加到

Movie

模型以及如何添加一個初始值設定項,将自動建立一個測試資料庫。

==============================翻譯==============================

修改後的

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); 
}      

這裡是不是覺得很奇怪了,就隻改了黃色背景的那倆行

效果如下以前使用者需輸入

http://..../movies/searchIndex/searchString="ghost"

現在隻需要輸入

http://..../movies/searchIndex/ghost

這就是MVC的約定大于配置

這東西文字說明真難組織...

能看懂明白就好,哥寫不出來了...

但是,即使您添加此

HttpPost

版本的

SearchIndex

方法,有這一切如何執行的限制。想象一下你想要添加書簽特定的搜尋或你想要的連結發送給朋友他們可以單擊看看同一篩選清單中的電影。請注意 HTTP POST 請求的 URL 是 GET 請求 (localhost:xxxxx/電影/SearchIndex) 的 URL 相同 — — 在 URL 本身沒有搜尋資訊。現在,搜尋字元串資訊作為窗體字段值發送到伺服器。這意味着您不能捕獲該搜尋資訊以建立書簽或在 URL 中發送給朋友。

解決方案是使用

BeginForm

,它指定 POST 請求應添加到 URL 的搜尋資訊和它應該被路由到公共版本的

SearchIndex

方法的重載。現有無參數

BeginForm

方法替換為以下内容:

這段大緻說的是一個post方法基于get方法查詢的基礎上