Rob Howard
在我的小時候,我每年都會花幾週的時間待在我的大家庭裡。身為一個年幼的美國小男孩我當時非常著迷荷蘭電力火車,一些在我的家鄉──德州達拉斯所沒有見過的事情。我的堂兄招待我搭乘他們的小船去看經過的火車。坐在靠近車軌的水上可以聽到漸近的火車,像是輕輕的口哨穿過鐵軌,直到火車呼叫而過時奏出一個緩慢的高潮。在考慮ASP.NET 2.0時使我不由想起了這件事。 ASP.NET 2.0已經十分接近而且我們大部分都在熱切期望它的發布能早點到來,我們甚至聽到了發布繼續越來越響的“嗚”聲。屆時我們寫軟體的方式將會改變,再一次。
微軟ASP.NET 2.0的目標是提供開發者的效能50%。然而,實際的效能提升似乎超過了預期。新的personalization, membership和角色管理特性拿掉了開發者的負擔,而其他的特性,像是資料綁定,也被簡化了。例如,我們熟悉且仍能支援的語法:
<%# DataBinder.Eval (Container.DataItem, "FirstName") %>
在ASP.NET 2.0 卻可以簡化為:
<%# Eval("FirstName") %>
不僅有大量的另人印象深刻的新特性,還有大量的極具意義的伺服器控制項。由於伺服器控制項像<ASP:login>控制項對membership的整合和新的data source和資料控制項伺服器控制項,ASP.NET程式設計模型將在ASP.NET 2.0中變得更強大。
在ASP.NET 2.0中System.Web類別庫的數量幾乎翻倍──涵蓋太多甚至需要雜誌專欄連載。為了真正理解這些改變的程度,您需要一本新的ASP.NET 2.0的書。我計劃在這撰寫一些專欄來突出一些比較重要的ASP.NET 2.0的新功能。本月刊我將重點放在導航和頁面流程,以眾人尋求的特性——提交給其它頁面能力作為開始。
跨頁投遞
我從遷移到ASP.NET開發者們那裡聽到抱怨最多的是頁面的回發模型,ASP.NET頁面可以擁有單一的<form>並且只能HTTP回發給自己,這樣所有的處理邏輯都將運行在這個頁面裡。
許多開發者,特別是那些熟悉ASP,喜歡控制<form>元素的,會了解ASP中可以指示<form>將自己的內容資料提交到何處和如何發送(HTTP Post 或HTTP Get),以及同一頁面上<form>的數量。但與ASP相比,ASP.NET中僅允許頁面只有一個<form runat=server>,並且只能回發給自己。這點可能令人十分懊惱,以下是ASP.NET2.0中發送給其他頁面的範例:
<%@ Page MasterPageFile="~/Site.master" Language="C#"
CodeFile="Source.aspx.cs"
Inherits="Source" %>
<ASP:Content ID="MainContent"
ContentPlaceHolderID="Main" Runat="server">
Enter your name:
<ASP:TextBox ID="NameBox" Runat="server"></ASP:TextBox>
<ASP:Button ID="Button1" Runat="server" Text="Submit" />
</ASP:Content>
Master Pages用來控制頁面佈局,帶有一個<ASP:content>區塊,有一些伺服器控制項可以接受使用者輸入。
如果打算將內容傳遞到另一個頁面,可以採用類似下面的伺服器程式碼:
Response.Redirect("Target.aspx?Name= " +
HttpUtility.UrlEncode(NameBox.Text));
這種技術的問題是當使用者點擊按鈕提交後,伺服器接受請求並發送回應令瀏覽器轉向Taget.aspx,這樣簡單的問題做了大量的工作!
能不能簡化工作呢?在ASP.NET 2.0中答案是肯定的。接下來示範改進後的程式碼:
<%@ Page MasterPageFile="~/Site.master" Language="C#"
CodeFile="Source.aspx.cs"
Inherits="Source" %>
<ASP:Content ID="MainContent"
ContentPlaceHolderID="Main" Runat="server">
Enter your name:
<ASP:TextBox ID="NameBox" Runat="server"></ASP:TextBox>
<ASP:Button ID="Button1" Runat="server" Text="Submit"
PostBackUrl="~/Target.aspx" />
</ASP:Content>
注意<ASP:Button>中的PostBackUrl屬性,這個屬性會通知按鈕不再執行預設的回傳而是直接提交資料到Target.aspx.
您可能想知道這是如何運作的,尤其是您熟悉ASP.NET的ViewState物件時。不過那超出了本文的範圍,當跨頁投遞特性被使用時頁面會新增一個隱藏域:
<input type="hidden" name="__PREVIOUSPAGE" id="__PREVIOUSPAGE"
value="p1-dFHlCpgH2alr1vkr3G21UIR7jOuzn074led6lbGf1KQ47_F25GwG0" />
有點像控制項樹所產生的視圖狀態,但它是給跨頁投遞驗證此頁的視圖狀態的碎片。您知道,當一個頁面被跨頁投遞給另一個頁面後,接受頁面要可以存取投遞頁的實例。本例中意味著Target.ASP可以存取Source.aspx的詳細資訊。事實上,更有效的方法是透過強型別管理器存取Source.aspx到Target.aspx的API。為了存取投遞頁(上個頁面),ASP.NET2.0特別為跨頁投遞提供一個頁面屬性:PreviousPage。
PreviousPage傳回投遞頁的實例,還有一個屬性是用來檢查是否是跨頁投遞:IsCrossPagePostBack。這個屬性類似現有的IsPostBack但是只有跨頁投遞發生時回傳true。
PreviousPage屬性可以有不同的行為,預設只簡單將上個頁面的實例作為Page類型傳回,但是,透過使用一個新的指令您可以讓PreviousPage屬性傳回一個強型別實例,來存取頁面的public成員。例如,將下面的程式碼加入Target.aspx:
<%@ PreviousPageType VirtualPath="~/Source.aspx" %>
現在可以在Target.aspx上使用PreviousPage屬性來存取Source.aspx的資料了。然而,為了存取伺服器控制項,像Source.aspx上的NameBox,您還需要編寫以下程式碼:
TextBox nameBox = PreviousPage.FindControl("NameBox") as TextBox;
換句話說,您必須使用FindControl來存取控制項樹。為什麼呢?伺服器控制項預設為受保護成員變量,為了真正簡單存取上個頁面的元素,您需要將Source.aspx上的屬性或方法顯露為public,然後下面的程式碼才能工作: TextBox nameBox = PreviousPage. NameBox;
跨頁投遞是ASP.NET非常棒的一個特性,有一些文章深入討論了跨頁投遞的技術細節,如果有興趣跨頁投遞是如何運作的,可以查看Dino Esposito在MSDN雜誌9月刊的Cutting Edge column(請見本人譯本:ASP.NET 表單(翻譯))。您很可能也會發現,如果您很精通ASP.NET,那麼您大多時候仍會繼續使用標準的頁面回發模型。 (譯者:言下之意,您如果是高手的話會不屑於此特性)
嚮導控制
透過跨頁投遞,可以輕鬆的給應用程式建立一個複雜的導航功能。然而,這個特性卻不能簡化您建立嚮導樣式的使用者介面。為了完成任務,無論線形或非線形,嚮導樣式的使用者介面都經常被設計。它提供給終端用戶一個親切的途徑完成一系列複雜的步驟,每個步驟都被打碎為很多塊。
在ASP.NET 1.x,精靈常透過一些技巧來實現:將多個<ASP:panel>伺服器控制項放在同一個頁面,透過使用者所在的位置切換可見性。在ASP.NET中寫一個嚮導不是一件易事,很多設計師的丟棄了嚮導,並且步驟流程的管理也很混亂。
ASP.NET中新的跨頁投遞能力可以用來解決嚮導問題,但是當需要非線性導航存在時就同樣是挑戰了。例如,步驟1,步驟2,跳過步驟3-5,步驟6,步驟3,步驟2,步驟6,ASP.NET 2.0 精靈控制項解決了大部分這類問題。還有,透過頁面回發模型替換跨頁投遞精靈的所有的輸入元素可以持續存取。
精靈控制功能上很大程度的接近ASP.NET 1.1中隱藏panel的方式。然而,嚮導控件顯露了一系列的<ASP:WizardStep>,它們可以包含任意數量的子控件,然而每個<ASP:WizardStep>需要有自己的unique ID,見圖1。嚮導控制頁管理所有的導航,支援線性和非線性導航,並且有vs完整的設計時支援。圖2示範了嚮導控件,左邊是基於link的非線性導航,右下是線性的按鈕導航。從開啟的任務選單,可以看到不僅僅是一個公共任務而是一個步驟清單允許在設計時切換步驟。
圖2 精靈在Visual Studio中的情形
精靈控制項的所有可見元素都是可以設定的。非線性連結可以用按鈕或刪除入口代替,上一步,下一步,完成線性導航元素也可以改變為圖片按鈕或連結。事實上,控制項所有的面貌都可以透過模板來配置。
在ASP.NET 1.1中編寫精靈控制項的一個困難點就是管理使用者應該身在何處。嚮導控制項透過顯露ActiveStep屬性簡化了此工作。 ActiveStep屬性可以查詢並決定目前哪個步驟是啟動的。嚮導的自然流程會按照實作宣告好的方式進行,流程可以透過MoveTo方法隨時改變。透過MoveTo,任意步驟可以被設定為ActiveStep,為了輔助導航和流程,也提供了幾個事件,見圖3。
新的嚮導控制項在蒐集使用者資訊時非常有用,不想ASP.NET 1.1中所有的基礎構造都要寫,ASP.NET把所有的工作都給您準備好了。嚮導控制太有用了,ast.net小組使用它作為CreateUserWizard控制項的基類,CreateUserWizard控制項用作Membership功能的一部分來建立使用者。
小節
跨頁投遞和<ASP:Wizard>控制項為ASP.NET開發者在應用程式中控制導覽流程帶來幾個新的選擇。跨頁投遞對於目前需要使用Response.Redirect 或Server.Transfer 情況非常有用。嚮導控制用來建構同時需要線形和非線形的複雜的資料蒐集的確很棒。
------------------------------------------------
圖1 精靈步驟
<ASP:Wizard runat="server" >
<WizardSteps>
<ASP:WizardStep ID="Step1">
Welcome!
</ASP:WizardStep>
<ASP:WizardStep ID="Step2">
What is your name: [TextBox1]
[Button1]
</ASP:WizardStep>
<ASP:WizardStep ID="Step3">
Thank you, [TextBox1.Text]!
</ASP:WizardStep>
</WizardSteps>
</ASP:Wizard>
-------------------------------------------- ---------
圖3 Navigation Events
Event | Description |
---|---|
ActiveStepChanged | Raised when the ActiveStep is set to a new WizardStep |
CancelButtonClick | Raised |
when the button identified as the Cancel button is clicked | FinishButtonClicksed | .
the | Next button is clicked |
PreviousButtonClick | Raised when the button identified as Previous button is clicked |
SideBarButtonClick | Raised when one of the SideBar links or buttons is clicked |