ASP.NET MVC ---模型在视图中的传递
最近刚学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()传递模型项的时候,会出现模型项为空的情况。可怕的是,我的模型传递并没有错误,视图也是该模型的强类型视图,就算调试也调试不出什么错误,结果我就关机重启,然后所有的问题都消失了!关机重启并不是解决问题的方式,只是因为那时候我想要睡觉了而已!如果有遇到类似问题的同学,也可以考虑和我一样:先关机睡一觉,然后再看看情况。