ASP.NET 表單 (翻譯) 多表單 多Form__.net

來源:互聯網
上載者:User
ASP.NET 表單 (翻譯) 多表單 多Form [ 2006-06-12 21:46:38 | 作者: Admin ] 字型大小: 大 | 中 | 小 Dino Esposito
Form(表單)是ASP.NET開發中重要的組成部分--沒有Form就沒有ASP.NET Web編程模型。Form不局限於純粹的HTML,但是在ASP.NET中會受到一些限制。對於ASP.NET頁面,Form可以提交自身,並且ASP.NET模型提供了控制項狀態管理和postback事件。由於ASP.NET的單一Form模型使得編寫ASP.NET應用程式簡單又便捷.

ASP.NET中表單上的限制可能聽起來怪異而武斷,但實際上跟ASP.NET模型有直接的作用。然而,有一種實際情況是ASP.NET 1.x form 模型所不支援的:在同一個頁面擁有多個,互不干涉的form。比如,您不能在某個頁面上添加一個搜尋文字框並將結果提交到另一個頁面.

在msdn雜誌2003年5月刊上,我寫了一個專欄關於ASP.NET 1.x的Form編程(參閱 Cutting Edge: Form-based Programming in ASP.NET),對於ASP.NET 2.0的介紹裡, 關於提交給不同的頁面這一主題的地址有一些變動。本文我將討論ASP.NET 2.0下的Form編程.

表單呈現
讓我們探索一下ASP.NET的表單世界,去瞭解表單(包括控制項)是如何實際呈現的。在ASP.NET頁面上,<form>標記可以是幾種容器控制項像<table>, <div>, 或 <body>的子控制項; 然而,在大多數頁面中,<form>只是簡單作為<body>的子節點。如果一個非容器控制項(比如TextBox)被放置在form標記之外,將會拋出一個執行階段錯誤(編譯時間不會對此進行檢查)。請看如下代碼,節選自TextBox的 AddAttributesToRender 方法:

protected override void AddAttributesToRender(HtmlTextWriter writer)
{
if (this.Page != null) this.Page.VerifyRenderingInServerForm(this);
...
}



調用頁面的VerifyRenderingInServerForm方法將會處理此工作。(當您自己編寫自訂伺服器控制項時應避免這種行為)

HtmlForm類
HtmlForm繼承自HtmlContainerControl,使得表單具有包含子控制項的能力。HtmlForm提供了對HTML<form>元素在伺服器端的編程訪問能力,其properties列表見圖1。從表中可以看到ASP.NET 1.x 和 ASP.NET 2.0的變化主要限於幾個properties。

一個表單必須擁有唯一的名字,未指定名字時ASP.NET會自動分配一個。可以通過ID或Name屬性給Form設定標識,同時設定時以ID屬性優先。可是有一點要注意,一些編程介面使用Name屬性來相容xhtml。在xhtml中,elements通過ID標識而不是Name,因此通常來講,最好以ID屬性為準。

表單的父物件是一個具有runat屬性的總容器控制項。如果這樣的控制項不存在,頁面對象被作為父物件。典型的伺服器端form的容器是標記為伺服器端對象的<table>或<div>。

圖2 列出了HtmlForm類中最常用的到一些方法。這些方法繼承於System.Web.UI.Control類。注意FindControl方法只搜尋form的直接子控制項。內部容器中的子控制項和表單子控制項的子控制項將不能被找到。

多表單管理
通常來講,投入單表單模型的懷抱而放棄對多表單系統的支援並不算是很大的犧牲。儘管一些頁面如果能使用multiple forms將會獲得更加致一致和自然的設計--至少對於那些包含有一定邏輯關係的輸入控制群組的表單 例如,一個頁面除了要給使用者提供資訊,還需要支援一個搜尋表單或者登入框表單。

您可以將搜尋和登入功能合并到ad hoc類並通過顯示資訊的同一頁面調用,然而這並不是構造代碼的最佳方法。

如果您正在將老的代碼移植到ASP.NET, 您可能覺得將登入和搜尋代碼置於另一個專門的頁面更容易些。可是您如何才能將那些頁面的資料提交到本頁呢。

在單表單模型裡,頁面總是提交自身而且也沒有給開發人員提供設定回傳目標的鉤子。對於HTML和ASP編程,表單的Action屬性是單一值,在ASP.NET的HtmlForm類中也不暴露此屬性。單表單模型跟ASP.NET平台整合的太緊密,您要麼採用要麼放棄——或者,做為一個附加的選擇就是可以用ASP的方式編寫代碼不使用伺服器表單。象下面要講到的,在ASP.NET 2.0裡,可以將資料提交到另一個頁面,但是這個特性是通過一些按鈕控制項的新增功能得以實現的。現在,我們先看看使用HTML的非伺服器端表單時有什麼棘手問題。

在ASP.NET中,當有多個HtmlForm控制項需要呈現時將會拋出異常。頁面中的第一個HtmlForm控制項被呈現後,會有一個布爾標記被設為true,此標記指示了是否有HtmlForm已被呈現,當另一個HtmlForm試圖呈現時,由於此標記已經被設定為true因而引發一個異常。

如果一個Web Form中包含了一個伺服器form和任意數量的不含有runat屬性的<form>標記不會導致任何錯誤。沒有runat屬性,任何標記都成為純粹單一的HTML而直接呈現(見圖3).

此頁麵包含2個表單,第二個是沒有ruan="server"屬性的HTML表單,因此被ASP.NET完全忽略。提供給瀏覽器的html中合法包含了兩個<form>元素,它們指向兩個不同的action URL。

然而從功能上來講此代碼有一個大的缺陷:不能使用ASP.NET編程模型來檢索用戶端表單action頁面上的提交資料。當編寫search.aspx時,對於用戶端表單的action頁面,不能對頁面的控制項藉助檢視狀態和提交資料來讀取和更新它們的狀態。(The apparent statefulness of ASP.NET server controls is obtained by making pages post to themselves)為了知道提交給search.aspx的資料,您必須採取針對ASP模型的直接在回傳資料中檢索的傳統風格:

protected void Page_Load(object sender, EventArgs e)
{
// Use the Request to retrieve posted data
string textToSearch = Request.Form["Keyword"].ToString();
...
// Use standard ASP.NET to populate the page UI
KeywordBeingUsed.Text = textToSearch;
}





可以使用 HttpRequest 對象協議規範中的集合(Page.Request等同於HttpContext.Current.Request)來檢索回傳的資料——對於POST方式時使用Form,GET方式時使用QueryString,或者想要相容對Form、QueryString、 ServerVariables 和 Cookies的訪問時使用Params。HttpRequest 對象會在頁面建立前將資料封裝,因此,頁面的任何事件都可以隨意調用Page.Request.對於自提交的ASP.NET頁面,不需要使用Request是由於可以藉助於一個強型別的編程模型,但是對於以前,可靠的 HttpRequest 對象依然是需要時為您而備的。

還有一件有趣的事要注意,當使用者點擊Search按鈕時,search.aspx被調用,它只接受那些Html 表單上發送回來的資料,不會有檢視狀態被回傳,也沒有額外的資料傳遞。如果必須提交資料到另一個頁面,使用傳統風格仍然是多數高效效能的明智之選。如隨後本專欄所述,ASP.NET 2.0 跨頁提交特性傳遞了相當大的,類別檢視狀態的資料域。

多 <form> 標記
如果多個伺服器端form出現在同一個web form上,將拋出異常。不易發現並不為人知的是,事實上web form可以包含任意數量的伺服器端form,只要同一時刻僅有一個可見並呈現。例如,一個頁麵包含有3個帶有runat="server"標記的<form>是允許的,但是僅有一個form的Visible屬性可以設定為true.通過啟用HtmlForm類的Visible屬性,您可以在頁面的生命週期改變活動的伺服器端form。這個小竅門不能解決同時有多個活動form的問題,但是有時還是有所協助的。

讓我們考慮一下圖4中的頁面,所有的<form>被標記為runat="server",但是只有第一個是可見的,互斥的form在ASP.NET 1.x中很順利的實現了一個嚮導。通過在按鈕事件中轉換各form的可見度,您可以獲得一個類嚮導的行為,參看圖5:



圖5 類嚮導頁面的運行效果


這個技巧在ASP.NET 2.0中基本沒用,因為您會發現有2個新控制項:MultiView 和 Wizard。MultiView控制項使用邏輯等同的互斥表單,可惜它使用panel而沒用正統的form。MultiView允許你定義多個互斥的HTML panel,並提供了API來切換這幾個panel的可見度,並確保同一時刻只有一個被啟用並可見。MultiView控制項沒有提供內建的使用者介面。Wizard控制項僅是MultiView加上一個類嚮導的預定義的UI塊,我在MSDN雜誌2004年11期上講解過它(參閱 Cutting Edge: The ASP.NET 2.0 Wizard Control )。

Cross-Page Posting(跨頁提交)
ASP.NET 2.0 提供了一個新的內建進位以覆蓋常規處理周期並允許頁面提交到另一個頁面。通常,postback發生在下面兩種方式之一:Submit按鈕激發或通過script激發。典型的按鈕提交自動指向form指定的提交地址,而如果提交是通過script時則更加靈活機動。在ASP.NET 2.0中,您可以配置某個控制項(尤其那些實現了新的IButtonControl介面的)使其可以提交給其他目標頁面,具體可以查閱cross-page posting。

實現IButtonControl的核心控制項是Button, ImageButton, 和 LinkButton。通常,通過實現IButtonControl,所有的自訂控制項都可以有表單中的按鈕同樣的效果。IButtonControl介面正是一個ASP.NET從1.0到2.0遷移時代碼重構的一個典型例子。IButtonControl介面彙總了ASP.NET 1.x支援的多數按鈕控制項(包括一些html按鈕控制項)的一些屬性。另外,一些新的屬性公布了新增的功能,象PostBackUrl 和 ValidationGroup,圖6詳細描述了IButtonControl介面。接下來的代碼片斷示範了如何使用:

<form runat="server">
<ASP:textbox runat="server" id="Data" />
<ASP:button runat="server" id="buttonPost" Text="Click"
PostBackUrl="target.aspx" />
</form>





當PostBackUrl屬性被設定,ASP.NET運行時為按鈕控制項的相應的html元素繫結一個新的JavaScript功能。將會使用新的WebForm_DoPostBackWithOptions函數取代常規我們使用的__doPostback函數,用戶端轉譯效果如下:

<input type="submit" name="buttonPost" id="buttonPost" value="Click"
onclick="BLOCKED SCRIPTWebForm_DoPostBackWithOptions(
new WebForm_PostBackOptions("buttonPost", "",
false, "", "target.aspx", false, false))" />





結果是,當使用者點擊按鈕時,當前的表單提交內容給指定的目標頁。那麼檢視狀態的情況呢。當含有可以cross-page posting的控制項時,頁面會建立一個name為__PREVIOUSPAGE的隱藏欄位,此域包含了提交頁的資訊。目標頁使用此資訊來建立一個完整狀態的引用來調用頁對象。

在目標頁,您可以使用Page類的新增的一個屬性PreviousPage來引用提交頁和頁面上所有的控制項。下面是目標頁面對form中某TextBox內容檢索的後台代碼:

protected void Page_Load(object sender, EventArgs e)
{
// Retrieves some posted data
TextBox txt = (TextBox) PreviousPage.FindControl("TextBox1");
...
}





通過使用Page類的PreviousPage屬性,可以訪問提交頁上聲明的任意輸入控制項.對輸入控制項的訪問是弱類型的並間接使用FindControl方法.擺在事實面前的問題是目標頁面並不知道關於提交頁類型的任何資訊.同樣地,它也不能提供對源頁面類的指定成員的訪問.

此外,注意FindControl僅僅尋找當前container中的控制項,如果你要找的控制項是在另一個控制項內部(比如模板),您必須首先取得這個container的引用然後再搜尋container來尋找那個控制項.為了避免完全藉助FindControl,還需要另一種途徑.

為了檢索提交頁面上的的值,FindControl將僅提供安全的選項當您預先不知道將會調用哪個目標頁時.然而,當在應用程式的上下文中使用cross-page posting時,將有機會確切知道的是誰將調用和如何調用這個頁面.這種情況下,您可以利用PreviousPageType指令使目標頁的PreviousPageType屬性強型別為源頁面類.在目標頁,添加下面的指令:

指令可以為兩個互斥屬性之一:VirtualPath 或 TypeName.VirtualPath指提交頁的URL,TypeName則指明調用頁的類型.PreviousPageType指令使目標頁PreviousPage屬性返回給定路徑上的頁面相同類型(或者TypeName屬性指定的類型)的一個對象引用,而事實本身是您不能直接存取輸入控制項.在ASP.NET中,每個頁面類包含了子控制項對應的protected成員.不幸的是,您不能調用外部類的受保護的成員.事實上,只有衍生類別可以訪問父類的受保護的成員.

為了達到這個目的,您必須在調用頁上在一個public屬性來進行提交頁資訊的訪問.例如,假象crosspostpage.aspx頁上包含一個名字為_textBox1的TextBox,為了使它能夠在目標頁訪問,必須在後台類增加如下代碼:

public TextBox TextBox1
{
get { return _textBox1; }
}



作為cross-page調用潛在可能的目標,不會自動將目標頁成為別的類型.通常目標頁總是被自身調用,例如通過一個超連結.這種情況發生時PreviousPage屬性返回null並且別的回傳相關的屬性(象IsPostBack)採用常規值.對於雙重功能的頁面,好的辦法是添加額外的代碼來分辨頁面的行為.下面的Page_Load事件中的代碼使頁面只工作於cross-page調用方式:

if (PreviousPage == null)
{
Response.Write("Sorry, that's not the right way to invoke me.");
Response.End();
return;
}



頁面重新導向
除了按鈕控制項的PostBackUrl屬性,ASP.NET提供了另一個頁面間傳遞控制項和值的機制:Server.Transfer方法.當你調用此方法,新頁面的URL不會反映到瀏覽器的地址欄,因為這種頁面轉向發生伺服器端--在用戶端不會有任何間接事件發生.下面的代碼示範了如何使用此方法來進行頁面定向:

protected void Button1_Click(object sender, EventArgs e)
{
Server.Transfer("targetpage.aspx");
}





注意下面對頁面中進行重新導向的調用代碼不會被執行.最後,Transfer只是頁轉向的方法.可是,卻對兩種情況十分有效:第一,用戶端的請求.例如,使用Response.Redirect.第二,同一個應用程式中某請求要在新的頁面請求被重用.

對於ASP.NET 1.x,可以通過使用http內容相關的Handler屬性擷取調用對象,象下面所示:

Page caller = (Page) Context.Handler;

由於Handler屬性返回了一個有效對象引用,主體頁可以訪問它的public成員,但是象我們上面討論過的不能直接存取頁面上受保護層級的控制項.

本編程模型也使用於ASP.NET 2.0, 不過,在 ASP.NET 2.0中,變得更簡單了,不再需要使用Handler.你可以使用與cross-page postings相同的編程模型並藉助一個非空的PreviousPage屬性和強型別訪問輸入欄位的@PreviousPageType指令來處理.那麼頁面如何才能檢測它是被server transfer調用還是cross-page postback?兩種方式下PreviousPage都是非空的,但是PreviousPage對象的Page.IsCrossPagePostBack在cross-page posting方式是為true,而erver transfer則為false.

小結
從一個頁面傳值到另一個頁面有很多種方法可以達成--cross-page posting,server transfer,HTML forms, cookies, session-state, query strings, 或者其他方法等等.那麼最有效是哪個呢。在 ASP.NET 2.0中,cross-page posting 和 server transfer提供了一個常見的編程模型,但卻潛在地通過View State移動了大塊的資料。而這些資訊是否真正需要依賴於目標頁面的描述。在很多情況下,目標頁面僅僅需要接收啟動運作的一些參數。if this is so,HTML用戶端表單可能用移動資料更加有效,儘管HTML表單需要一個類ASP的編程模型。

ASP.NET 2.0為HtmlForm類增加了一些新的特性,然而核心行為並未改變,因此提交自身仍是ASP.NET編程的主要方法。您可以混合用戶端form和伺服器form,也可以擁有多個伺服器form不過同一時間內僅有一個可見。

問題和評論請發送至 cutting@microsoft.com.


作者簡介
Dino Esposito在意大利羅馬工作,任職講師兼顧問。《Programming ASP.NET》和新書《Introducing ASP.NET 2.0》(兩書均由Microsoft Press出版)的作者,他將大部分時間用於講授ASP.NET和ADO.NET方面的課程以及在各種會議上演講。
如果希望與Dino取得聯絡,請發送email至 cutting@microsoft.com 或者瀏覽他的blog網站: http://weblogs.ASP.NET/despos。


--------------------------------------------------------------------------------

譯自 MSDN Magazine 2005年9月刊 .

--------------------------------------------------------------------------------
圖 1 Properties of the HtmlForm Class

Property ASP.NET 1.x ASP.NET 2.0 Description
Attributes Inherited from Control. Gets a name/value collection with all the attributes declared on the tag.
ClientID Inherited from Control. Gets the value of UniqueID.
Controls Inherited from Control. Gets a collection object that represents the child controls of the form.
DefaultButton String property. Gets or sets the button control to display as the default button on the form.
DefaultFocus String property. Gets or sets the button control to give input focus when the form is displayed.
Disabled Gets or sets a value indicating whether the form is disabled. Matches the disabled HTML attribute.
EncType Gets or sets the encoding type. Matches the enctype HTML attribute.
ID Inherited from Control. Gets or sets the programmatic identifier of the form.
InnerHtml Inherited from HtmlContainerControl. Gets or sets the markup content found between the opening and closing tags of the form.
InnerText Inherited from HtmlContainerControl. Gets or sets the text between the opening and closing tags of the form.
Method Gets or sets a value that indicates how a browser posts form data to the server. The default value is POST. Can be set to GET if needed.
Name Gets the value of UniqueID.
Style Gets a collection of all cascading style sheet (CSS) properties applied to the form.
SubmitDisabledControls Indicates whether to force controls disabled on the client to submit their values, allowing them to preserve their values after the page posts back to the server. False by default.
TagName Returns "form".
Target Gets or sets the name of the frame or window to render the HTML generated for the page.
UniqueID Inherited from Control. Gets the unique, fully qualified name of the form.
Visible Gets or sets a value that indicates whether the form is rendered. If false, the form is not rendered to HTML.

--------------------------------------------------------------------------------
圖 2 Methods of the HtmlForm Class

Method ASP.NET 1.x ASP.NET 2.0 Description
ApplyStyleSheetSkin Applies the skin in the defined page theme in the manner defined by StyleSheetTheme.
DataBind Calls the DataBind method on all child controls.
FindControl Retrieves and returns the control that matches the specified ID.
Focus Sets the input focus to a control.
HasControls Indicates whether the form contains any child controls.
RenderControl Outputs the HTML code for the form. If tracing is enabled, caches tracing information to be rendered later, at the end of the page.

--------------------------------------------------------------------------------
圖 3 Server and Client Forms in the Same Page
<html>
<body>
<table><tr><td>
<form id="form1" runat="server">
<h2>Ordinary contents for an ASP.NET page</h2>
</form>
</td>
<td>
<form method="post" action="search.aspx">
<table><tr>
<td>Keyword</td>
<td><input type="text" id="Keyword" name="Keyword" /></td>
</tr><tr>
<td><input type="submit" id="Go" value="Search" /></td>
</tr></table>
</form>
</td>
</tr></table>
</body>
</html>



--------------------------------------------------------------------------------
圖 4 Markup for an ASP.NET 1.x Wizard-Like Page
<html>
<body>
<form id="step0" runat="server" visible="true">
<h1>Welcome</h1>
<asp:textbox runat="server" id="Textbox1" />
<asp:button ID="Button1" runat="server" text="Step #1"
OnClick="Button1_Click" />
</form>
<form id="step1" runat="server" visible="false">
<h1>Step #1</h1>
<asp:textbox runat="server" id="Textbox2" />
<asp:button ID="Button2" runat="server" text="Previous step"
OnClick="Button2_Click" />
<asp:button ID="Button3" runat="server" text="Step #2"
OnClick="Button3_Click" />
</form>
<form id="step2" runat="server" visible="false">
<h1>Finalizing</h1>
<asp:button ID="Button4" runat="server" text="Finish"
OnClick="Button4_Click" />
</form>
</body>
</html>



--------------------------------------------------------------------------------
圖 6 IButtonControl Interface

Property Description
CausesValidation Boolean value indicating whether validation is performed when the control is clicked.
CommandArgument Gets or sets an optional parameter passed to the button's Command event along with the associated CommandName.
CommandName Gets or sets the command name associated with the button that is passed to the Command event.
PostBackUrl Indicates the URL that will handle the postback triggered through the button control.
Text Gets or sets the caption of the button.
ValidationGroup Gets or sets the name of the validation group to which the button belongs.
Visible Boolean value indicating whether the button control is rendered.
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.