若要將使用者重新導向其他頁面,除了傳統的 Hyperlink、Response redirect、Server transfer 以外,ASP.NET 2.0 還新增了特有的「跨網頁公佈 (Cross-page posting)」機制。
在「跨網頁公佈」中,會使用 HTTP POST 呼叫 target page。相對於傳統的網址 URL QueryString 帶參數的方式外,「跨網頁公佈」還可把 source page 中所有「控制項」的 ID 及內容 (包括使用者輸入值),一併都自動帶到 target page 中。要啟用該機制,必須在 source page 中,透過 Button、ImageButton、LinkButton 控制項的 PostBackUrl 屬性,將頁面 PostBack 到其他的 WebForm 網頁 (JavaScript 中會以新的 WebForm_DoPostBackWithOptions 函式,取代以前的 __doPostback 函式),而非 PostBack 到本身頁面。
傳統的網址 URL QueryString 帶參數,若要傳到 target page 的值很多,程式員必須手動寫一大堆參數名稱及其值,不但缺乏彈性,且必須花時間寫許多 code;而「跨網頁公佈」由於可以在 target page 中,直接捉到前一頁 source page 中的控制項,因此可以少寫許多代碼。
接著來看一個範例。如下圖 1,第一頁 (soruce page) 中有一個 GridView 控制項,和兩個 TextBox 讓使用者輸入關鍵字做模糊查詢;第二頁 (target page) 有一個 FormView 控制項,和兩個頁面上看不到的 HiddenField 控制項,HiddenField 是用來暫存從第一頁中,透過「跨網頁公佈」所傳過來,使用者輸入的兩個查詢關鍵字。
圖 1 透過 Cross-page posting 在兩個頁面之間傳值
public partial class Page1_GridView : System.Web.UI.Page
{
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
for (int i = 0; i < GridView1.Rows.Count; i++)
{
// 透過 Button 的 PostBackUrl 屬性,將網頁 PostBack 至另外一頁
((Button)GridView1.Rows[i].FindControl("btnRO")).PostBackUrl = "Page2_FormView.aspx?type=1";
((Button)GridView1.Rows[i].FindControl("btnEdit")).PostBackUrl = "Page2_FormView.aspx?type=3";
((Button)GridView1.Rows[i].FindControl("btnDelete")).PostBackUrl = "Page2_FormView.aspx?type=4";
代碼 1 第一頁 (source page) 傳送值的關鍵代碼
public partial class Page2_FormView : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack) // 若頁面是第一次執行
{
// 取得第一頁,使用者在兩個 TextBox 裡輸入的搜尋關鍵字,暫時藏在本頁(第二頁)的兩個 HiddenField,以便待會返回第一頁時,能再用來填回第一頁的兩個 TextBox 中,當作第一頁重新 SELECT 的 SQL WHERE 條件
if (PreviousPage != null)
{
// 透過 IsCrossPagePostBack 屬性來判斷,並取得第一頁中控制項的 ID 及其內容值
if (PreviousPage.IsCrossPagePostBack)
{
// tbCOMP_NUM、tbCOMP_NAME 為前一頁(第一頁)的兩個 TextBox 的 ID
hfKeyWord1.Value = ((TextBox)PreviousPage.FindControl("tbCOMP_NUM")).Text;
hfKeyWord2.Value = ((TextBox)PreviousPage.FindControl("tbCOMP_NAME")).Text;
}
}
}
} // end of Page_Load()
代碼 2 第二頁 (target page) 接收值的關鍵代碼
如果 source page 和 target page 在同一個 Web application 中,target page 還能夠存取 source page 中,class 的 public properties (屬性)。做法如下,用「指示詞 (Directive)」去存取:
<%@ PreviousPageType VirtualPath="~/Page1_GridView.aspx" %>
或
<%@ Reference VirtualPath="~/Page1_GridView.aspx" %>
此外,「跨網頁公佈」還可用在多個「使用者控制項 (User Control)」之間的通訊和巡覽 (navigate)。
「跨網頁公佈」其實是透過 ViewState 達成的。若在 source page 中使用「跨網頁公佈」時,會建立一種叫做「__PREVIOUSPAGE」的新型隱藏欄位。此欄位會存放有關 posting page 的資訊,讓 target page 用來建立有關「呼叫端頁面」物件的 stateful reference。如下方範例所示:
<input type="hidden" name="__PREVIOUSPAGE" id="__PREVIOUSPAGE"
value="p1-dFHlCpgH2alr1vkr3G21UIR7jOuzn074led6lbGf1KQ47_F25GwG0" />
這個名稱也剛好對應到 .NET 2.0 新增的 Page 類別的 PreviousPage 屬性。
「跨網頁公佈」的 target page 會將 source page 的 ViewState 移除掉,並自己另存一份;並在 target page 載入後,將儲存的 ViewState 存入與 source page 相同、但為新生的 PreviousPage instance,因此 target page 才能存取到 source page 的控制項內容或 public properties。但由於「跨網頁公佈」會牽涉到「另存 ViewState、實體化、還原 ViewState 到 PreviousPage instance」等一系列動作,相對的也比較消耗 Web server 的系統資源。若 ViewState 內容很龐大時,儲存及還原的成本也會相對提升。因此「跨網頁公佈」和傳統的 URL QueryString 傳參數的使用時機,必須由程式員自行拿捏,而非在開發新專案或元件時,一律都套用最新一代的技術。
-------------------------------------------------
(本文在版工的舊 Blog 中,發表日期為 2006/08/02)