最近實在是太忙,客戶丟了一個框架,沒有任何說明文檔,更沒有所謂的技術支持,一直忙于學習,最后好歹還有點頭緒,話不多說,MVC的學習是不能拉下的,就當前小白的我,認為MVC中的M并不是想象中的那樣簡單,一般用作前后臺的數據交互。
什么是模型?什么是模型綁定?
微軟出的《ASP.NET MVC 5編程實戰》中有講到,模型分領域模型、視圖模型。個人理解視圖模型就是一個數據庫對應的實體類。領域模型狹義的來說包括視圖模型和一些其他的屬性。
視圖傳遞參數+值(或實體對象),Action中接收。看似是一瞬間完成的。中間其實是需要經過兩個步驟,①通過實現IValueProvider接口來獲取視圖中(Form、RouteData、QueryString、HttpFileCollection)請求值。②在通過實現IModelBind中的方法將這些獲取的請求參數、值綁定到Action中對應的形參上。同樣這里接口中方法都是默認去調用的,如果有需要,可以進行自定義編寫實現其接口的方法。
比如,最常見的 將數據庫中A表的部分數據顯示在視圖V中,然后進行增刪該查操作。這里在視圖V中,最上面會引用 該表的實體類@model 項目名.文件夾.實體類,再根據Razor語法,就可以用Lambda表達式點出來 該表的列名
創建--前臺表單數據提交到Controller
@model MVC_plug.Models.Students @{ ViewBag.Title = "Create"; } <h2>Create</h2> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Students</legend> <div class="editor-label"> @Html.LabelFor(model => model.Stu_Name) </div> <div class="editor-field"> @Html.EditorFor(model => model.Stu_Name) @Html.ValidationMessageFor(model => model.Stu_Name) </div>
這里 瀏覽器解析Razor 語法是 將 BeginForm 解析為From表單,對于HTML來說是,是不存在實體類之說的,表單提交的值僅僅是以鍵值對的方式進行存儲后提交到指定的Action中.也就是將視圖中的請求參數與action中的形參進行匹配、綁定。這就是簡單模型綁定。
1 .在Controller中對應的Action的方法體中 將 Student 作為參數來接收
[HttpPost] public ActionResult Create(Students students) { if (ModelState.IsValid) { db.Students.Add(students); db.SaveChanges(); return RedirectToAction("Index"); } return View(students); }
既然View中不存在將提交的內容綁定到 實體類中,那么輸入的數據為什么在Action的參數Student中可以點出來? 實際上 View 中Post提交的數據 是以鍵值對的方式進行存儲,然后映射到提交的Action中的 Student中,前提是 View中的鍵名(Name名字)必須要等于 實體類型的屬性名,否則無法綁定
2.在Controller中對應的Action的方法體中直接設置參數來接收值 ()
public ActionResult Create(string Stu_Name,string Tel,string phone)
運行項目,其中Stu_Name、Tel 有值,phone 無值,當然這只是佐證,如果在前臺的View 中設置的名字不一樣,后臺用Student去接收,同樣也會得到空值。
后臺傳遞數據到前臺
1. 顯示某數據列表 ,同樣是后臺Controller 將 查詢的結果 賦值給一個實體類對象,用反射也好,反序也行,再 Return View(實體類);
前臺最上面要引用 @model 指向實體類 來接收傳遞的數據,因為是同一個實體,直接映射到前臺,最后View 中進行顯示即可
2. 當然還可以選擇 ViewData 和ViewBag 在后臺的Action中賦值,然后在View中接收,關于這兩者的比較,這里簡單的整理下
ViewData 的 ViewDataDictionary 是一個特殊的字典類,當在控制器中使用 ViewData["CurrentTime"] = DateTime.Now; 其實是將這個值以鍵值對的形式進行存儲
ViewBag不再是字典的鍵值對結構,而是dynamic動態類型,它會在程序運行的時候動態解析
MVC 高級編程中提高兩者的區別
①只有當要訪問的關鍵字是一個有效的C#標識符時,ViewBag 才起作用。
例如,如果在ViewData["Key With Spaces"]中存放一個值,那么就不能使用ViewBag訪問。因為這樣根本就無法通過編譯。
②動態值不能作為一個參數傳遞給擴展方法。因為C#編譯器為了選擇正確的擴展方法,在編譯時必須知道每一個參數的真正類型。如果其中任何一個參數是動態的,那么就不會通過編譯。
例如,這行代碼就會編譯失敗:@Html.TextBox("name",ViewBag.Name)。要使這行代碼通過編譯有兩種方法:第一是使用ViewData["Name"],第二是把ViewBag.Name值轉換為一個具體的型:(string)ViewBag.Name 。
說白了,ViewBag 就是在ViewData的升級版,兩者只能在Action中起作用,當然,兩者的數據是可以相互訪問。ViewBag的底層是ViewData,所以當兩者定義同一屬性不同值的時候,視圖中顯示的值永遠是ViewData所定義的值
// GET: Test public ActionResult Index() { ViewBag.Name = "顓頊viewbag"; ViewData["Name"] = "顓頊viewdata"; return View(); }
前臺視圖中顯示的值,均是 顓頊viewdata
@Html.TextBox("Name",(string)ViewBag.Name) <br/> @Html.TextBox("Name",ViewData["Name"])
此外當用 TextBoxFor +強類型視圖時,若在控制器中給實體類賦值,視圖中又用New{ Value=“” } 來賦值,則實體對象中的值將被覆蓋。
public ActionResult Index() { Test te = new Test(); te.Name = "顓頊"; TestViewModel testViewModel = new TestViewModel() { test = te, Tests = new List<Test>() }; ViewBag.Name = "顓頊viewbag"; ViewData["Name"] = "顓頊viewdata"; return View(testViewModel); }
如下視圖均顯示顓頊viewdata(Value中首字母V需大寫)
@Html.TextBoxFor(m => m.test.Name,new { Value= ViewData["Name"]}) <br /> @Html.TextBoxFor(m => m.test.Name, new { Value = (string)ViewBag.Name })
市人皆大笑,舉手揶揄之
文章列表