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 卻可以簡化為:
不僅有大量的另人印象深刻的新特性,還有大量的極具意義的伺服器控制項。由於伺服器控制項像<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 情況非常有用。嚮導控制項用來構建同時需要線形和非線形的複雜的資料搜集的確很棒。
下一次我會剖析 ASP.NET 2.0 中sitemap的URL重寫。 問題和建議請發送到xtrmasp@microsoft.com.
作者簡介
Rob Howard 是 Telligent Systems 的創始人,專門從事高效能 Web 應用程式、知識庫管理員和協作系統方面的工作。Rob 以前受雇於 Microsoft,他在那裡協助設計了 ASP.NET 1.0、1.1 和 2.0 的基礎結構。要聯絡 Rob,請訪問 rhoward@telligentsystems.com。
轉到原英文頁面
圖 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 |
FinishButtonClick |
Raised when the button identified as the Finish button is clicked |
NextButtonClick |
Raised when the button identified as 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 |