最近剛學ASP.NET MVC,雖然只是敲了個簡單的常式,但收穫還是有的。
MVC中最基本的東西就是:Model(模型),View(視圖),Controller(控制器)。對於這三者的關係必須要非常清楚,尤其是在程式的運行中,這三者是怎樣相互配合。簡單來講,控制器決定行為,模型存放資料,視圖顯示行為處理資料後的結果(或者是單純的顯示資料),實際上遠比這個複雜得多。
控制器由一系列操作組成,這些操作一般都是返回一個ActionResult,而ActionResult包括Json,View等等。先說說View。
View()方法的使用非常簡單。預設無參的重載版本返回的是與操作同名的視圖,像是下面這樣:
public ShoppingController : Controller{ public ActionResult Index(){ return View(); }}
返回的就是/Views/Shopping/Index.cshtml。良好的MVC編程方式就是將相關的東西放在一起,像是將與ShoppingController有關的視圖放在一個單獨的檔案夾Shopping就比較方便了。
但是我們也可以指定該操作顯示的視圖,像是這樣:
return View("Shopping");
就不是顯示預設的Index.cshtml,而是Shopping.cshtml。
神奇的是,我們還可以通過View()傳遞模型給相應的視圖。
像是這樣:
public ActionResult Index(int id){ return View(id);}
就能將模型項System.Int32傳遞給視圖Index.cshtml。神奇吧,int竟然是模型項!這沒有什麼好驚訝的,因為在MVC中,所謂的模型就只是一些C#類型,而System.Int32本身就是一個類型,所以,可以被當做模型項處理也是很正常的。
傳遞模型項的目的當然就是使用該模型項,像是下面這樣:
@model System.Int32 ...<h2>@Model</h2>
我們就可以在視圖中使用該模型項了,但是必須匯入該模型,就是通過@(相當於C#的using,java的import)。匯入模型必須指定命名空間,Int32的命名空間就是System.Int32,但如果是我們自訂的類型,就必須完整的指定該類型的命名空間。使用的時候,也是使用@(也就是Razor文法),@Model就是使用該模型id的值。當然,如果是自訂的類型,而且是包含有方法的類型,我們可以通過@Model.+ method來調用相關的方法。
在寫常式的時候,我就發現一個問題,就是會有這樣的錯誤提示:未將對象引用設定為對象執行個體(NullReference)。這時我們就要細心的檢查,是否有匯入相關的模型,操作中有沒有傳參,參進來的模型項是否是null。
向視圖傳遞模型非常重要,比如說,我們想要在視圖中顯示一個模型的狀態,那麼,我們就必須將目前狀態的模型傳遞給視圖,這些都是通過簡簡單單的傳參動作就能搞定。也許,我們可以在視圖中引用該模型。確實,我們可以通過jQuery來通過HttpContext來獲得該模型的相關狀態,像是這樣:
function handleUpdate() { //Load and deserialize the returned JSON data var json = context.get_data(); var data = Sys.Serialization.JavaScriptSerializer.deserialize(json); //Update the page elements if (data.ItemCount == 0) { $("#row-" + data.DeleteId).fadeOut("slow"); } else { $("#item-count-" + data.DeleteId).text(data.ItemCount); } $("#cart-total").text(data.CartTotal); $("#update-message").text(data.Message); $("#cart-status").text("Cart(" + data.CartCount + ")"); }
相應的視圖部分代碼如:
@foreach (var item in Model.CartItems) { <tr id ="row-@item.RecordId"> <td> @Html.ActionLink(item.Album.Title, "Details", "Store", new{ id = item.AlbumId }, null) </td> <td> @item.Album.Price </td> <td id ="item-count-@item.RecordId"> @item.Count </td> <td> <a href ="#" class ="RemoveLink" data-id ="@item.RecordId">Remove from cart</a> </td> </tr> } <tr> <td> Total </td> <td></td> <td></td> <td id ="cart-total"> @Model.CartTotal </td> </tr>
可以看到,jQuery是通過$來執行的,像是$("#cart-total")就是擷取id為cart-total的HTML元素(好吧,這類似於javascript,但jQuery本來也就是一個javascript的開源庫)。$並不是一個符號,它是一個函數名,就是一個函數的別名,像是這樣:
$(function(){ ...});
它就是參數中匿名函數的別名。當我們傳遞一個匿名函數作為參數的時候,就相當於我們假定該函數是在瀏覽器完成構建HTML的文件物件模型後立即執行的函數。這樣的假定是有好處的,防止函數中與DOM(Document Object Model,即文件物件模型)相衝突的指令碼,導致DOM無法順利載入。
如果認為$只是單純的函數別名那就錯了,它的作用遠非如此。像是上面的擷取元素id,就發揮了選取器的作用,我們還可以進一步指定相關元素中的子項目:
$("#cart-total img")
這樣就是指定id為cart-total的HTML元素中的img元素。如果是javascript,就需要好幾個函數了。
$的神奇之處就是,當它作為選取器的時候,會返回一個包含零個或多個匹配元素的封裝集(wrapped set),我們還可以在該封裝集上繼續調用相關的方法(這些方法必須是依賴於封裝集的方法,當然,它們同樣是返回封裝集)。這就是方法鏈。
我不知道該原因是否是VS2012的問題,有時候我通過View()傳遞模型項的時候,會出現模型項為空白的情況。可怕的是,我的模型傳遞並沒有錯誤,視圖也是該模型的強型別視圖,就算調試也調試不出什麼錯誤,結果我就關機重啟,然後所有的問題都消失了!關機重啟並不是解決問題的方式,只是因為那時候我想要睡覺了而已!如果有遇到類似問題的同學,也可以考慮和我一樣:先關機睡一覺,然後再看看情況。