在asp.net 1.x 版本中,頁面都是提交到自己本身,并不能方便的指定需要提交的目的頁面。例如firstpage.aspx中的button只能提交到firstpage.aspx,而不能提交到secondpage.aspx。很多時候,asp.net 1.x這樣工作方式使我們的開發方式受到不少限制。熟悉asp/jsp/php的朋友大概很不習慣,因為以前經常使用的提交方式突然無法使用,雖然也有解決這個問題的方法(演示webcast),可是過程太煩瑣,不甚方便。令我們高興的是,asp.net 2.0中有了跨頁面提交的簡單方法。
簡單的例子
首先看看下面的代碼,firstpage.aspx中的button通過指定postbackurl屬性可以提交到指定的頁面:
firstpage.aspx
<%@ page language="c#" %>
<!doctype html public "-//w3c//dtd xhtml 1.0 transitional//en" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd">
<script runat="server">
public string username {
get {
return this.txtname.text;
}
}
protected void button1_click(object sender, eventargs e)
{
label1.text = "postback from self. your name is: " + txtname.text;
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<meta content="text/jscript" http-equiv="content-script-type" />
<title>first page</title>
</head>
<body>
?。糵orm id="form1" runat="server">
?。糳iv>
?。糷3>the frist page</h3>
your name:
<asp:textbox id="txtname" runat="server" />
?。糰sp:label id="label1" runat="server" enableviewstate="false" /><br />
?。糱r />
<asp:button id="button1" runat="server" text="postback to same page" onclick="button1_click" /><br />
?。糱r />
?。糰sp:button id="button2" runat="server" text="postback to second page" postbackurl="~/secondpage.aspx" /><br />
?。?div>
</form>
</body>
</html>
secondpage.aspx
<%@ page language="c#" %>
<%@ previouspagetype virtualpath="~/firstpage.aspx" %>
<!doctype html public "-//w3c//dtd xhtml 1.0 transitional//en" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd">
<script runat="server">
protected void page_load(object sender, eventargs e)
{
this.label1.text = "your name is : " + previouspage.username;
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>second page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h1>this is the second page</h1>
<p><asp:label id="label1" runat="server"></asp:label> </p>
</div>
</form>
</body>
</html>
打開firstpage.aspx,輸入內容并按下"postback to second page"按鈕提交,頁面就會提交到secondpage.aspx,輸入的內容也會顯示在secondpage.aspx上。注意firstpage.aspx中button2新增的postbackurl屬性,還有secondpage.aspx中的@previouspagetype指令。這些新增的內容,正是asp.net 2.0 中的跨頁提交的方案的組成部分。
大家可能會發現,在使用asp.net 2.0 的跨頁面提交功能的時候,目標頁面都是在源頁面的窗口中打開的。但有時候我們需要在新的窗口中打開目標頁面,通過修改源頁面中<form>的屬性可以實現這一點。如下面的代碼所示:
<form id="mainform" target="_blank" runat="server">
讀取源頁面的信息
asp.net 2.0中,button控件有個新增的屬性postbackurl,用來設置需要提交的目標頁面。因為只要指定button控件的postbackurl屬性就可以提交到其它頁面,我們可以在頁面中使用多個控件配置其postbackurl的屬性,提交到不同的頁面。當然也可配置多個頁面提交到同一個頁面。
在跨頁面提交之后,通常我們需要從源頁面中讀取控件的信息(即由瀏覽器發送的信息),以及源頁面的公共屬性。
讀取控件的值
asp.net 2.0的page類新增了一個previouspage屬性。顧名思義,目標頁面中的這個屬性包含對源頁面的引用。這樣就可以在目標頁面中通過previouspage屬性訪問源頁面的信息,我們一般使用findcontrol方法來查找源頁面上的控件并讀取這些控件的值。下面的代碼說明了該方法的使用:
if (page.previouspage != null)
{
textbox txtname = (textbox)page.previouspage.findcontrol("txtname");
if (txtname != null)
{
label1.text = txtname.text;
}
}
當我們想查找源頁面中控件屬于另一個控件或者是模板之中,就不能直接使用findcontrol方法來讀取它,而是應該先獲取對該容器的引用,然后才能在該容器中查找要獲取的控件。下面的例子中,firstpage.aspx頁面中包含一個panel控件,其id為mainpanel,它還包含id為username的textbox控件。具體代碼如下:
panel mainpanel = (panel)previouspage.findcontrol("mainpanel");
if (mainpanel != null)
{
textbox username = (textbox)mainpanel.findcontrol("username");
if (username != null)
{
label1.text = username.text;
}
}
else
{
label1.text = "cannot find username control.";
}
讀取源頁面的公共屬性
一旦在目標頁面中獲取了previouspage的引用,就能訪問源頁面中公共控件的屬性,同樣也可訪問源頁面中的公共屬性。當然,我們需要預先在源頁面中公開需要被訪問的屬性方可在目標頁面中訪問。
若要獲取源頁面的公共成員,必須先獲取對源頁面的強類型引用。就像第一個例子中,我們可以使用@previouspagetype指令來指定源頁面,它有兩個屬性分別為:virtualpath和typename。使用virtualpath屬性指定來源頁的虛擬路徑(包含文件名),也可以使用typename指定源頁面的屬性。注意只能指定其中的一個,兩者都指定就會失效。如第一個例子中所示:
<%@ previouspagetype virtualpath="~/firstpage.aspx" %>
如果使用了@previouspagetype指令,目標頁面中的previouspage 屬性被強類型化為源頁面的類。因此,可以直接引用源頁面的公共成員。要獲取對源頁面的強類型引用的另一種方法是在目標頁面中包含一個@reference 指令,就像引用要在頁面中使用的其它任何類型一樣。在這種情況下,你可以在目標頁面中獲取目標頁面的previouspage屬性并將其強制轉換為源頁面的類型,如下面的代碼所示:
sourcepage_aspx sourcepage;
sourcepage = (sourcepage_aspx) previouspage;
label1.text = sourcepage.username;
讀取源頁面中的form信息
如果源頁面和目標頁面屬于同一個 asp.net 應用程序,則目標頁中的previouspage屬性包含對源頁面的引用。在沒有使用@previouspagetype指令的情況下,目標頁面中previouspage 屬性類型化為page。
注意,如果該頁不是跨頁發送的目標頁面或者目標頁面位于不同的應用程序中,則不會初始化previouspage屬性。
如果源頁面和目標頁面屬于不同的應用程序,甚至是不同的網站,那就無法直接獲取源頁面上控件的值,但可以從request.form中讀取發送的數據。還有一個需要注意的問題,因為源頁面的視圖狀態經過hash處理,所以不能從源頁面中讀取視圖狀態。如果要在源頁面中存儲值并讓這些值可供其他應用程序中的目標頁使用,可以將這些值作為字符串存儲在源頁面的隱藏字段中,并在目標頁面中通過 request.form 來訪問它們。 判斷是否為跨頁面提交
跨頁面提交的時候,源頁面控件的內容被提交到目標頁面,然后瀏覽器執行post操作(注意,不是get)。在asp.net 1.x中由于頁面都是自己提交給自己,可以通過page的ispostback屬性來判斷是否為頁面提交。但是在跨頁面提交的時候,目標頁面的ispostback屬性為false。如果要判斷是否為跨頁面提交,可以對目標頁面的previouspage屬性返回的引用頁面的iscrosspagepostback屬性進行判斷,如下面的代碼所示:
if(previouspage != null)
{
if(previouspage.iscrosspagepostback == true)
{
label1.text = "跨頁面提交";
}
}
else
{
label1.text = "非跨頁面提交";
}
注意,如果當前頁面不是跨頁面提交的目標頁面,則其previouspage屬性為空。
跨頁面提交 vs server.transfer
asp.net 2.0中,無論是跨頁面提交還是使用server.transfer操作,都可以使用previousoage屬性來獲取對源頁面的引用。如果要區分它們,可以使用上面介紹的方法。
下面是跨頁面提交與server.transfer之間的一些區別:
屬 性 | 跨頁面提交 | server.transfer |
| ispostback | false | false |
| previouspage | 源頁面的引用 | 源頁面的引用 |
| previouspage.iscrosspagepostback | true | false |
| iscrosspagepostback | false | false |
| iscallback | false | false |
跨頁面提交是客戶端瀏覽器的行為,而server.transfer則是服務器端的行為。在后面的小節中,我們會分析跨頁面提交時客戶端瀏覽器是如何實現提交的。
對跨頁面提交的簡單分析
在上面的例子中,我們都提到設置button的postbackurl屬性來實現跨頁面提交。其實只要實現ibuttoncontrol接口的控件均可以實現這一點。button, imagebutton, 和 linkbutton都實現了ibuttoncontrol接口。通過實現ibuttoncontrol,自定義控件也可以有表單中的按鈕所具有的跨頁面提交的功能。ibuttoncontrol接口聚合了asp.net 1.x支持的多數按鈕控件(包括一些html按鈕控件)的一些屬性。
當設置了button控件的postbackurl屬性之后,asp.net運行時將為按鈕控件的所對應的的html元素綁定一段新的javascript代碼。使用新的 webform_dopostbackwithoptions函數取代常規以前所使用的__dopostback函數。具體的html代碼示例如下:
<input type="submit" name="button2" value="postback to second page" button2", "", false, "", "secondpage.aspx", false, false))" id="button2" />
上述代碼中的webform_dopostbackwithoptions函數與webform_postbackoptions函數的javascript代碼如下:
function webform_postbackoptions(eventtarget, eventargument, validation, validationgroup, actionurl, trackfocus, clientsubmit) {
this.eventtarget = eventtarget;
this.eventargument = eventargument;
this.validation = validation;
this.validationgroup = validationgroup;
this.actionurl = actionurl;
this.trackfocus = trackfocus;
this.clientsubmit = clientsubmit;
}
function webform_dopostbackwithoptions(options) {
var validationresult = true;
if (options.validation) {
if (typeof(page_clientvalidate) == 'function') {
validationresult = page_clientvalidate(options.validationgroup);
}
}
if (validationresult) {
if ((typeof(options.actionurl) != "undefined") && (options.actionurl != null) && (options.actionurl.length > 0)) {
theform.action = options.actionurl;
}
if (options.trackfocus) {
var lastfocus = theform.elements["__lastfocus"];
if ((typeof(lastfocus) != "undefined") && (lastfocus != null)) {
if (typeof(document.activeelement) == "undefined") {
lastfocus.value = options.eventtarget;
}
else {
var active = document.activeelement;
if ((typeof(active) != "undefined") && (active != null)) {
if ((typeof(active.id) != "undefined") && (active.id != null) && (active.id.length > 0)) {
lastfocus.value = active.id;
}
else if (typeof(active.name) != "undefined") {
lastfocus.value = active.name;
}
}
}
}
}
}
if (options.clientsubmit) {
__dopostback(options.eventtarget, options.eventargument);
}
}
用戶點擊按鈕時,當前表單將內容提交給postpageurl屬性所指定的目標頁面。當頁面中含有可以實現跨頁面提交功能的控件時,頁面會創建一個name為__previouspage的隱藏字段,此字段包含了源頁面的信息。目標頁面則使用此信息來創建一個完整狀態的引用來調用源頁面對象。上述隱藏字段的相關html代碼示例如下:
<input type="hidden" name="__previouspage" id="__previouspage" value="nd3_1gqjdsueac3ylyvz-eqrktzzlyfhliiff7mmqvbdmwzmfi8hg4mzx5pfzy0n0" />
總 結
asp.net 2.0 新增的跨頁面提交功能,讓我們的開發過程有了更加靈活的選擇。在使用跨頁面提交的時候,我們要根據實際的情況選擇合適的方式來讀取源頁面中的信息。如果源頁面與目標頁面處于同一個應用程序之內,我們可以選擇使用@previouspagetype指令來指定源頁面,這樣就可以使用強類型引用的好處。
由于asp.net中的每個頁面類所包含的子控件對應的是protected成員,所以您不能直接通過previouspage引用來訪問源頁面中的控件,而先需要將源頁面中需要被訪問的屬性公開出來。同時,建議您只將需要的信息作為公共屬性公開,以減少可能被潛在的惡意用戶使用的信息。