在 上一篇文章中,我們看到了建構使用者界面的基本實作。但在現實世界中,我們需要使用更加複雜的方法來開發出更複雜的使用者界面。例如,使用者不希望點選應用程式中的多個連結才浏覽到他們想要的資訊,他們希望能夠很友善的在一個視圖中便取得他們要求的所有資訊。
在ASP.NET MVC中,我們仍然可以使用使用者控件來建立一個應用程式中的可重用元件—它們被稱為部分視圖(Partial View)。自從ASP.NET MVC 1.0始就提供了這一支援。在本文中,我們還要使用這種方法,并且結合MVC 2.0中提供的一個新功能—Html.Action,聯合起來使用。
一、建立使用者界面
在Web表單中,當使用者界面變得極其複雜時,開發人員往往通過建構一個巨大的ASPX頁面或者把複雜的邏輯分解成單獨的使用者控件或自定義控件的途徑來克服這一複雜性。通常情況下,隻有當非常有必要進行重用時才把自定義控件派上用場,而使用者控件則被經常使用,這是因為它們易于使用且設計簡單的緣故。
在ASP.NET MVC中,上述這些類似功能可以借助于部分視圖(相當于使用者控件)或自定義HTML助理類(相當于自定義控件)來實作。
借助于MVC 2.0中新引入的一個功能—Html.Action方法,可以使一個行為方法把它的響應直接注入到一個父級視圖中。而第二個行為方法傳回待注入的一個視圖,我們可以把這個方法實作為一個自我包含的實體或類型。局部視圖可以建立一個表單以回寄到它的控制器,而主視圖可以回寄到另一個不同的控制器。這種實作表單間互動的思路可謂清晰易懂,但在實作這種方法時仍然有一些問題值得關注。下面,讓我們研究一個具體的示例。
清單1—使用Html.Action方法的表單示例
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<p>
Main Action
</p>
<% Html.BeginForm(); %>
<div>
Name: <%= Html.TextBox("IndexName")%>
</div>
Value: <%= Html.TextBox("IndexValue")%>
<input type="submit" value="save" />
<% Html.EndForm(); %>
<%= Html.Action("Custom", new { title = "Test Title" })%>
</asp:Content>
在上面代碼中,我們有一個簡單的表單。本表單包含了兩個字段。接下來跟着的是調用一個名稱為Custom的行為方法(位于相同的控制器内)。這個輔助行為方法以路由值形式調用控制器方法本身,并把控制器的名稱(可選)和任何形式的資料傳遞到該控制器中。
清單2中給出的部分視圖已經被注入并成為主視圖的一部分。注意,這個視圖定義了自己的表單(這是一種使部分視圖自包含的方式)。任何到伺服器端的回寄都被重定向到這個Custom行為方法中,而不是重定向到主行為方法。這一點特别重要。
清單2—注入部分視圖的示例
Custom Action
<% Html.BeginForm("Custom", "RenderingActions"); %>
Name: <%= Html.TextBox("CustomName")%>
Value: <%= Html.TextBox("CustomValue")%>
這個部分視圖是自包含式的,除了可以使用與父視圖所有相同的資料資源(例如HTTP上下文和路由資料)外,它并不知道父視圖的其他内容。現在,我們建立了一個表單,它在浏覽器中的樣子如圖1所示。

▲
圖1—示例表單
其中,Main Action部分是通過父視圖建立的使用者界面,而Custom Action被建立為一個局部視圖。處理表單回寄的控制器如清單3所示。
清單3—控制器代碼
public class RenderingActionsController : Controller
{
[HttpGet, ChildActionOnly]
public ActionResult Custom()
return PartialView();
}
[HttpPost]
public ActionResult Custom(FormCollection form)
[HttpGet]
public ActionResult Index()
return View();
public ActionResult Index(FormCollection form)
你可能搞不清這究竟是如何工作的,畢竟我們有兩個不同的過程在這裡起作用:主表單的内容和子表單的内容。我們知道,在MVC中不存在任何ViewState的概念,回寄子視圖不會自動保留父視圖的資料,了解這一點是非常重要的。當點選相應于子控制器方法的送出按鈕時,它回寄自身的内容卻并不回寄父視圖的内容。是以,針對這種情形應當預先規劃一個很好的應對政策。
在我們進一步讨論這一點之前,讓我們來看一看把内容寄送回行為方法的基本标記代碼。下面是我們的示例中的兩個表單對應的标記代碼。請注意其中的表單行為方法和控制引用。
清單4—HTML标記代碼
<form action="/RenderingActions" method="post">
Name: <input id="IndexName" name="IndexName" type="text" value="" />
Value: <input id="IndexValue" name="IndexValue" type="text" value="" />
</form>
<form action="/RenderingActions/Custom" method="post">
Name: <input id="CustomName" name="CustomName" type="text" value="" />
Value: <input id="CustomValue" name="CustomValue" type="text" value="" />
上述代碼中,我們建立了兩個不同的表單(你也可以建立更多的表單),它們将各自進行獨立的回寄。另外,上述代碼中包含了相對于Web表單架構的一個重要變更,因為以前隻能是由一個Web表單包含所有的控件。
二、使用AJAX技術
前面的做法有可能導緻為您的控制器添加大量額外的代碼。被注入的局部視圖執行一個到行為方法Custom的回寄操作,這反過來又導緻第二階段的再處理,并重定向回到原來的視圖以顯示新的資料。這其中會導緻大量的工作。使用AJAX技術則能夠節省一些處理時間。清單5取代了清單2中的部分視圖,它能夠以異步方式寄送表單資料。
清單5—使用AJAX表單的代碼
<div id="customresponse"></div>
<% using (Ajax.BeginForm("AjaxCustom", new AjaxOptions
{ UpdateTargetId = "customresponse" }))
{%>
<%}%>
請注意上面使用的UpdateTargetID屬性。此屬性用于指定要把響應資訊注入到一個特定的HTML元素目标。此更新的目标是在以AJAX模式回寄時調用方法的傳回結果對應指定的目标。表單本身在表單的元素内向伺服器發出回寄,并在清單6中進行處理。這一點特别值得注意。
清單6—傳回一個響應
public ActionResult AjaxCustom(FormCollection post)
if (Request.IsAjaxRequest())
return Content("Success");
else
當在一個視圖中操作多個行為時,表單必須關注是以同步還是以異步方式發出的請求。如果請求是一個Ajax請求,結果的内容将被注入到更新的目标(一個DIV元素)。我們不希望傳回部分視圖,因為這會把使用者界面複制到我們的自定義響應的DIV(更新目标)中。另外,我們并不需要使用更新目标來重新加載現有的使用者界面,因為在AJAX請求模式下使用者界面從未消失。
另一方面,當不使用AJAX方式時同步請求回寄到伺服器端,需要你來處理整個請求。隻傳回成功的消息是不能按預期那樣工作,因為那時使用者界面會消失。當請求不使用Ajax回寄到伺服器端時,你要自己處理整個的請求,而且為此您将擁有完全的控制權。這意味着,你必須針對每一個同步請求傳回整個部分視圖使用者界面,并且要關注何時可能發生這種情況。處理上述兩種情形可能要求您使用用戶端JavaScript技術。
在這個例子中,正是發生了上述情況,因為主視圖中的送出按鈕并沒有使用AJAX表單送出其内容,因而引發了到伺服器端的一個完整的回寄。由于MVC讓我們全面控制相應于每一個請求所呈現的内容,是以我們必須負責傳回相同的使用者界面資訊。
三、使用JQuery
JQuery架構能夠與ASP.NET MVC良好地協作。借助于JQuery,我們可以輕松地實作使用AJAX方式把資料以GET和POST寄送到伺服器端。ASP.NET MVC架構能夠以與ASP.NET MVC的用戶端元件同樣的方式檢測一個AJAX請求。下面,讓我們來看一下這樣的例子。
清單7—結合JQuery使用HTML.Action的代碼
JQuery Ajax Index
<div id="JQueryCustomParent">
<%= Html.Action("JQueryCustomIndex")%>
請注意上面代碼中并沒有使用一個DIV元素來包裝部分視圖(從JQueryCustomIndex傳回),這使得我們可以更容易确定要更新的目标區域。
在使用JQuery的時候應當注意幾個問題。第一,要確定你替換掉更新區域中的全部内容,是以在我們的自定義DIV範圍内的一切内容都必須清除并進行替換。第二,發生AJAX替代時部分視圖中的JavaScript代碼并不被執行;這意味着,腳本必須駐留在此視圖中,并且視圖必須要了解要更新的部分(這意味着視圖和局部視圖之間是緊耦合的,除非你做一些額外的工作來防止這一點)。清單8中提供了執行更新的腳本。
清單8—更新部分視圖的代碼
<script type='text/javascript'>
function attachToForm(){
$("#JQueryCustomParent").find("form:first").submit(function(e){
e.preventDefault();
$.post($(this).attr("action"),$(this).serialize(),
function(data){
$("#JQueryCustomParent").replaceWith($("<div/>")
.attr("id", "JQueryCustomParent").html(data));
attachToForm();
});
$(document).ready(function(){
</script>
JQuery在加載時會被關聯到我們的目标DIV中的第一個表單中。當送出時,預設的送出執行将被取消,而由jQuery執行回寄。此回寄将使用新的DIV及其内容替換掉我們的目标DIV。當更換内容時,我們失去了對送出處理程式的控制權。之後,這一過程需要重新連接配接(雖然我們也可能通過使用jQuery中的另一個事件處理方法來糾正這個重新連接配接問題)。
于是,局部視圖送出資料,JQuery阻擋表單資料的送出并執行到伺服器端的回寄,并使用從控制器行為方法傳回的新内容替換原先的HTML内容,然而所有這些對使用者來說都不會有任何異樣的感覺。
四、結論
ASP.NET MVC 2中增加了一個Html.Action方法允許多個行為方法出現在同一個視圖内,這是一個真正強有力的功能改進。但是,你必須小心注意在多個表單的情況下表單資料是如何回寄到伺服器端的。這對開發人員提出了較高的要求。針對這個問題,你可以使用AJAX技術加以補救,你可以選擇使用内置的MS AJAX,也可以是JQuery。
【相關文章】: <a href="http://kb.cnblogs.com/page/73293/" target="_blank">巨大轉變!ASP.NET MVC2行為方法新改進</a> <a href="http://kb.cnblogs.com/page/72445/" target="_blank">巨大轉變!教你使用ASP.NET MVC2新功能</a> <a href="http://kb.cnblogs.com/page/72166/" target="_blank">巨大轉變!ASP.NET MVC2使用者界面新實踐</a>