现在的位置: 首页 > 综合 > 正文

MVC专题研究(三)——数据绑定和传送

2013年03月28日 ⁄ 综合 ⁄ 共 4384字 ⁄ 字号 评论关闭

在今天这个章节里主要和大家侃侃在MVC中如何进行数据绑定和传输的问题。

 

 一、HTML页面数据传输机制:

                如果你之前学习过ASP或者PHP,建议你完全可以跳开这一章节,因为您应该对纯HTML页面的数据传输规律了如指掌;但是如果你是一个纯ASP.NET程序员,建议你应该先从这里起步——因为ASP.NET过于优秀的设计会使你“一叶障目,不见泰山”——在完全不了解HTML页面数据传输的情况下,学习MVC设计模式显然是不可能的。

                一个普通的HTML页面(假如你曾经尝试右键鼠标,然后“查看源代码”查看你的运行的aspx页面),你将会发现这样一些东西(以下是截取和本章节有关的片段):

<form method="post" action="WebForm1.aspx" id="form1">

<input type=”hidden” id=”…”…../>

<input type=”text” id=”…” …./>

<input type=”submit” value=”submit”…./>

</form>

                ASP.NET中那些所谓的服务器控件的本质还是HTML控件,只不过在编译和运行的过程中被解析成了标准的HTML代码返回请求的客户端了。你拖拽的一个按钮(Button)被解析成了一个submit按钮,该按钮是一个提交按钮。必须放置在form中,否则就会发生错误——为什么呢?因为你运行你的ASPX页面的时候点击这个按钮,观察IE偏右的状态栏中发现进度条会突然“一闪而过”,伴随着您的当前页面刷新了一次。这个功劳应该归功于Form,注意看action这里一块——WebForm1.aspx,这个不正式你现在运行的页面名称?是的,也就是说,当你点击了这个本质是submit的按钮的同时,由于它在Form中,浏览器自动读取action中的路径,像服务器发出一个WebForm1.aspx页面的请求而已。当发出请求时,你在文本框(被解析成了“<input type=”text”……>”)输入的东西就会自动跟随当前那个请求被发送到action所指定的页面。

                Action的路径可以是“相对路径”和“绝对路径”:

所谓相对路径就是从根目录开始加上自己当前页面的所在的路径(比如你的这个HTML页面在根路径的“files”文件夹下,那么此时路径是:http://localhost:[端口号]/,加上action中的页面所在的路径和action那个请求的文件名,变成:http://localhost:[端口号]/files/WebForm1.aspx。此时它就会到你根目录的files文件夹下找WebForm1.apsx页面,找不到就返回一个出错的信息了。

绝对路径就是不取决于当前文件的路径,用人为的方式直接从根目录开始指定,以“/”开头。如果你是action=”/WebForm1.aspx”,那么如果这个页面在files文件夹下,就会抛出一个找不到的异常,因为你指定从根目录下搜寻该页面的。

                Method是指定发送的方式。如果你想验证我的这句话,那么不妨你就创建两个HTML文档,其中page1<body>标签下应该存在这样一些内容:

                <form action=”page2” method=”get”>

                                <input type=”text” value=”Hello” name=”txt”…/>

                                <input type=”submit” value=”submit”/>

                </form>

                当您点击submit按钮,你将会发现地址栏上是http://.../page1.html?txt=Hello这样的类似内容,可见当前页面包含在Form里的东西的的确确可以传输到另外一个页面。如果改成post,包含问号的这一部分就会完全消失,但是这不代表没有将值传过去。因为接受页面也是HTML类型,所以“暂时”无法接受并且显示数据得以验证。如果是服务器页面(*.aspx),直接可以使用Response.Write(Request[“txt”])的方式输出得以验证了。

 

二、MVC中数据传输形式:

                仔细查看我的MVC组织架构,MvcDemo是一个根目录(相当于http://localhost:[端口号]的部分),因为我的URL定义是{controller}/{action}形式,所以直接以绝对路径的形式出现“action=/Controller名”。这就是MVCaction路径的写法。

                然后我们再来看看当一个action接受了从远处客户端请求的参数,如何获取呢?学习过ASP.NET的人理所当然Request[id]方法。当然这是一个。实际上,在接受Form表单的参数还有两种方法:

              1)使用FormCollection类。你只要把函数写成XXX (FormCollection params)的形式,直接从params[string key]的方式也可以获得。这个在获取表单数据的时候几乎和直接Request[id]一样,没有多大意思。不过后续的数据绑定就有好戏看了。

                2)使用函数(方法)参数,就像我一样——使用和表单中一些input等控件中name同名的参数而已,因为MVC会自动绑定。不过再次提醒您——有些参数不一定存在(比如刚开始的当前页数是没有的,为null的,此时如果让系统自动转化成int肯定会发生错误),那么我的建议就是对于某些基本类型最好使用int?的形式,或者是采用DefaultSettingsValue(默认值)来表示(如果没有值,自动采用默认值)。

 

三、MVC中数据自动绑定:

                AddItemEdit中不知道你注意到一个问题没有——我没有使用以上两种方式进行获取参数,然后实例化一个类,分别给其属性赋值,最后在执行Linq的保存……我就是把SaveTypeSaveItem的参数直接使用了一个类,形式如下:

                Public  ActionResult SaveType (HomeFinanceType type)

或许你会提出“我怎么在传输的过程中去传递一个类以便实例化?”的问题,实际上,你观察我的AddItem中每一个页面的”TextBox”或者是”TextArea”的名称都是映射HomeFinanceType的属性名称,这样就会自动进行绑定了。当然,可以缺省一些参数,那么type中那个缺省的是null

前面说过FormCollections 也可以绑定,不过似乎必直接类绑定要“麻烦”点,你要额外待用内部函数UpdateModel<T>的形式进行绑定,以便使得提交的数值会自动变更到你设定的那个类中,它有两种形式,假设我存在这样的代码:

HomeFinanceType type = new HomeFinanceType();

1Update<HomeFinanceType>(type);

2Update<HomeFinanceType>(type, new {“typeName”});

                第一个是缺省的,表示将key逐一映射成该实例type的属性,然后分别取对应的value给赋值,如遇不存在的自动设置null;第二个是表示将指定的某个key映射成属性,然后取数值进行赋值。

 

 四、MVC中数据回传绑定:

          ViewControllerMVC竟然可以那样智能般地上传绑定类和零散的参数。那么当在Controller中修改了参数之后,我们如何回传到某个页面呢?如果观察笔者的代码,你发现笔者主要使用了以下两种大方法:

直接让某个View继承一个泛型的ViewPage<T>,这样您可以直接使用Model获取参数,此时分两种情况:

1)如果是单一的类,你可以直接使用<%=Model.Property%>进行输出。

2)如果是一个集合类,您就可以使用foreach(var item in Model)的形式遍历输出。由于具备智能感知,因此您无需担心。

可惜的是,一个页面在C#中只能继承一个(泛型)类,那么如果要多个呢?比如Edit视图中的收支选项和整个页面需要的某个类(我让整个页面继承了ViewPage<HomeFinanceDetails>),那么选项怎么办?此时您不妨使用ViewDataTempData。它们都是HashTable的形式出现,您可以在Controller中给它们赋值,然后传递到那个View中,在那个对应的View中用强制转换的方式获得

          或许读者要疑问:ViewDataTempData的区别是什么?ViewData只对当前的View有效,而TempData存储在Session中,但是用过一次后就被自动删除了,因此只能经过一次Controller就报废了

您不妨看看以下的例子:(假设有两个Controller名字为C1C2,分别有两个方法C1View1(2)C2View1(2)):现在这样做——

【例1,验证ViewData的作用域】

Public ActionResult C1View1(…)

{

          ViewData[“data”]=”Hello”;

          return View();

}

Public ActionResult C1View2(..)

{

         ViewData[“data2”]=”Hello2”;

         return View(“C1View1”);

}

看看C1View1页面输出这样两个会怎么样?然后自己改成TempData尝试呢?

【例2,验证TempData的作用域】

Public ActionResult C1View1(…)

{

          TempData[“data”]=”Hello”;

          return View(“C2View1”);

}

Public ActionResult C2View1(…)

{

          TempData[“data2”]=”Hello”;

          return RedirectToAction(C1View1);

}

自己分别在不同的页面输出看看呢?你就明白了。

 

抱歉!评论已关闭.