MVC专题研究(三)——数据绑定和传送
在今天這個章節里主要和大家侃侃在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的路徑可以是“相對路徑”和“絕對路徑”:
v?所謂“相對路徑”就是從根目錄開始加上自己當前頁面的所在的路徑(比如你的這個HTML頁面在根路徑的“files”文件夾下,那么此時路徑是:http://localhost:[端口號]/,加上action中的頁面所在的路徑和action那個請求的文件名,變成:http://localhost:[端口號]/files/WebForm1.aspx。此時它就會到你根目錄的files文件夾下找WebForm1.apsx頁面,找不到就返回一個出錯的信息了。
v?“絕對路徑”就是不取決于當前文件的路徑,用人為的方式直接從根目錄開始指定,以“/”開頭。如果你是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名”。這就是MVC的action路徑的寫法。
??????????????? 然后我們再來看看當一個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中數據自動綁定:
??????????????? 在AddItem和Edit中不知道你注意到一個問題沒有——我沒有使用以上兩種方式進行獲取參數,然后實例化一個類,分別給其屬性賦值,最后在執行Linq的保存……我就是把SaveType和SaveItem的參數直接使用了一個類,形式如下:
??????????????? Public? ActionResult SaveType (HomeFinanceType type)
或許你會提出“我怎么在傳輸的過程中去傳遞一個類以便實例化?”的問題,實際上,你觀察我的AddItem中每一個頁面的”TextBox”或者是”TextArea”的名稱都是映射HomeFinanceType的屬性名稱,這樣就會自動進行綁定了。當然,可以缺省一些參數,那么type中那個缺省的是null。
前面說過FormCollections 也可以綁定,不過似乎必直接類綁定要“麻煩”點,你要額外待用內部函數UpdateModel<T>的形式進行綁定,以便使得提交的數值會自動變更到你設定的那個類中,它有兩種形式,假設我存在這樣的代碼:
HomeFinanceType type = new HomeFinanceType();
1)Update<HomeFinanceType>(type);
2)Update<HomeFinanceType>(type, new {“typeName”});
??????????????? 第一個是缺省的,表示將key逐一映射成該實例type的屬性,然后分別取對應的value給賦值,如遇不存在的自動設置null;第二個是表示將指定的某個key映射成屬性,然后取數值進行賦值。
?
?四、MVC中數據回傳綁定:
????????? 從View到Controller中MVC竟然可以那樣智能般地上傳綁定類和零散的參數。那么當在Controller中修改了參數之后,我們如何回傳到某個頁面呢?如果觀察筆者的代碼,你發現筆者主要使用了以下兩種大方法:
v?直接讓某個View繼承一個泛型的ViewPage<T>,這樣您可以直接使用Model獲取參數,此時分兩種情況:
1)如果是單一的類,你可以直接使用<%=Model.Property%>進行輸出。
2)如果是一個集合類,您就可以使用foreach(var item in Model)的形式遍歷輸出。由于具備智能感知,因此您無需擔心。
可惜的是,一個頁面在C#中只能繼承一個(泛型)類,那么如果要多個呢?比如Edit視圖中的收支選項和整個頁面需要的某個類(我讓整個頁面繼承了ViewPage<HomeFinanceDetails>),那么選項怎么辦?此時您不妨使用ViewData和TempData。它們都是HashTable的形式出現,您可以在Controller中給它們賦值,然后傳遞到那個View中,在那個對應的View中用強制轉換的方式獲得。
????????? 或許讀者要疑問:ViewData和TempData的區別是什么?ViewData只對當前的View有效,而TempData存儲在Session中,但是用過一次后就被自動刪除了,因此只能經過一次Controller就報廢了。
您不妨看看以下的例子:(假設有兩個Controller名字為C1和C2,分別有兩個方法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);
}
自己分別在不同的頁面輸出看看呢?你就明白了。
?
轉載于:https://www.cnblogs.com/serviceboy/archive/2009/11/25/1610552.html
總結
以上是生活随笔為你收集整理的MVC专题研究(三)——数据绑定和传送的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [转]php初级教程(七)一个新闻管理系
- 下一篇: FMS应用实例 - 从FMS服务器读取文