程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> .NET實例教程 >> 深入理解ASP.NET的Postback

深入理解ASP.NET的Postback

編輯:.NET實例教程
說道ASP.Net的Postback,就得說Web Page的生命周期,但是Web Page的生命周期卻不是三言兩語就能夠說得清楚的,所以在這裡單純站的編程的角度,撇開Web Page 的生命周期淺談Postback。

我們知道,無論是ASP.NET1.x,2.0,甚至是以後的版本,ASP.NET最終Render到ClIEnt端通過浏覽器浏覽的都是一樣:一個單純的Html。ClIEnt通過Submit Form的方式將填入Form的數據提交給Server進行處理。我們現在來看看ASP.Net整個Postback程序處理的過程。

首先我們通過一個Sample來看ASP.Net如何處理一個通過Click一個Button引起的Postback。下面是Web Page的Html:

 


<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.ASPx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xHtml1-transitional.dtd">
<html XMLns="http://www.w3.org/1999/xHtml">
<head runat="server">
    <title>Test Page</title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <asp:Label runat="server" ID="LabelMessage" ForeColor="red"></ASP:Label>
        </div>
        <div>
            <ASP:Button runat="server" ID="Button1" Text="Button1" OnClick="Button1_Click" OnCommand="Button_Command"     CommandArgument="Button1" />
            <ASP:Button runat="server" ID="Button2" Text="Button2" OnClick="Button2_Click" OnCommand="Button_Command"    CommandArgument="Button2" UseSubmitBehavior="false" />
            <ASP:Button runat="server" ID="Button3" Text="Button3" OnClick="Button3_Click" OnCommand="Button_Command"    CommandArgument="Button3" UseSubmitBehavior="false" />
        </div>
    </form>
</body>
</Html>

很簡單,定義了3個Button,分別注冊了他們的兩個Event:Click和Command。3個Button的Command Event Hander是一樣的:Button_Command,通過指定的CommandArgument來讓Event Handler判斷到底是哪個Button觸發了Command  Event。

下面是Code Behind:

 


using&n -bsp;System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class _Default : System.Web.UI.Page
{  

    protected void Page_Load(object sender, EventArgs e)
    {
       
    }
    protected void Button1_Click(object sender, EventArgs e)
    {
        string message = string.Format("The {0} event of {1} is fired", "Click", "Button1");
        this.LabelMessage.Text = message;
    }
    protected void Button2_Click(object sender, EventArgs e)
{
        string message = string.Format("The {0} event of {1} is fired", "Click", "Button2");
        this.LabelMessage.Text = message;
    }
    protected void Button3_Click(object sender, EventArgs e)
    {
        string message = string.Format("The {0} event of {1} is fired", "Click", "Button3");
        this.LabelMessage.Text = message;
    }

    protected void Button_Command(object sender, CommandEventArgs e)
    {
        string message = string.Format("The {0} event of {1} is fired", "Command", e.CommandArgument);
        this.LabelMessage.Text += "; " + message;
    }
}

我們來運行這個Page,並Click某個按鈕(比如Button2):

 


我們通過最上方的Message可以看出,Button2的Click Event和Command先後觸發。

這篇Blog的主旨就是從方法調用的角度講述整個程序運行的過程:從Html 被Render到ClIEnt端,到用戶Click某個按鈕,輸入被Postback到Server端,並觸發兩個Event,執行Event Handler打印出相關的Message。

首先我們來看看ASP.Net設計的Page Render到ClIEnt端的Html是什麼樣子:

 


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xHtml1-transitional.dtd">
<html XMLns="http://www.w3.org/1999/xHtml">
    <head>
        <title>
            Test Page
        </title>
    </head>
    <body>
        <form name="form1" method="post" action="Default.ASPx" id="form1">
            <div>
                <input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
                <input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
                <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTA0NDQ2OTE5OWRk281L4eAk7iZT10hzg+BeOyoUWBQ=" />
            </div>

<script type="text/Javascript">
                <!--
var theForm = document.forms[''form1''];
if (!theForm) {
    theForm = document.form1;
}
function __doPostBack(eventTarget, eventArgument) {
    if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
        theForm.__EVENTTARGET.value = eventTarget;
        theForm.__EVENTARGUMENT.value = eventArgument;
        theForm.submit();
    }
}
// -->
</script>

<div>
<span id="LabelMessage" ></span>
</div>
<div>
    <input type="submit" name="Button1" value="Button1" id="Button1" />
    <input type="button" name="Button2" value="Button2" onclick="Javascript:__doPostBack(''Button2'','''')" id="Button2" />
    <input type="button" name="Button3" value="Button3" onclick="Javascript:__doPostBack(''Button3'','''')" id="Button3" />
</div>
</form>
</body>
</Html>

上面的HtmlBody部分大體包括3個部分:

1.   定義了3個hidden fIEld:

 


<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />                
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTA0NDQ2OTE5OWRk281L4eAk7iZT10hzg+BeOyoUWBQ=" />

從他們的命名可以看出他們分別代表的意思:__EVENTTARGET代表觸發Event的Control的Unique name;__EVENTARGUMENT代表為Event Handler定義的額外的參數;__VIEWSTATE:代表的是VIEwstate。

2.   一段script:



<script type="text/Javascript">
                <!--
var theForm = document.forms[''form1''];
if (!theForm) {
    theForm = document.form1;
}
function __doPostBack(eventTarget, eventArgument) {
    if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
        theForm.__EVENTTARGET.value = eventTarget;
        theForm.__EVENTARGUMENT.value = eventArgument;
        theForm.submit();
    }
}
// -->
</script>
定義了一個__doPostBack function完成Postback的操作,該function只有區區3行代碼,前兩行通過參數對上面定義的兩個hidden fIEld賦值,然後向Server端提交表單。

3.   一段Html對應通過ASP.Net定義的Web Control。

 



<div>
<span id="LabelMessage" ></span>
</div>
<div>
    <input type="submit" name="Button1" value="Button1" id="Button1" />
    <input type="button" name="Button2" value="Button2" onclick="Javascript:__doPostBack(''Button2'','''')" id="Button2" />
    <input type="button" name="Button3" value="Button3" onclick="Javascript:__doPostBack(''Button3'','''')" id="Button3" />
div>

我們定義的3個Button被轉化成3個能向Server端提交表單的<input > Tag, 但是他們提交表的方式卻不一樣,第一個以<input type="submit">的方式提交,後面兩個通過調用Javascript的方式提交表單(<input type="button">)。對於一個System.Web.UI.WebControls.Button,默認采用第一種提交方式,但是我們通過設置UseSubmitBehavior屬性(這個屬性時ASP.Net 2.0新加的,1x沒有相應的設置),改變其表單提交的行為。

當用戶Click Button2的時候,調用__doPostBack,並傳入兩個參數:一個代表出發Event的對象的Unique name,也就是Button2的名稱,另一個描述Event的額外信息的參數,這裡不需要,所以這裡是空字符串。在__doPostBack中把這兩個參數賦值給兩個Hidden FIEld:__EVENTTARGET,__EVENTARGUMENT。然後向Server端提交表單,完成Postback。

然後我們來看看Server如何處理這個Postback,關於Web Page的生命周期在這裡就不詳細介紹了。Server端通過__EVENTTARGET這個hidden fIEld的值找到對應的Server端的Control,通過Reflection確定該Control是否實現了System.Web.UI.IPostBackEventHandler Interface。如果該Control確實實現了該Interface,那麼調用Page的RaisePostBackEvent方法,這是一個Virtual的方法,可以被Override。我們來看該方法的定義。

 


protected virtual void RaisePostBackEvent(string eventArgument)
{
    base.ValidateEvent(this.UniqueID, eventArgument);
    if (this.CausesValidation)
    {
        this.Page.Validate(this.ValidationGroup);
    }
    this.OnClick(EventArgs.Empty);
    this.OnCommand(new CommandEventArgs(this.CommandName, this.CommandArgument));
}

這個方法也很簡單,先進行Validation,然後先後出發兩個Event:OnClick 和OnCommand,隨後調用對應的Event handler,這和我們的輸出結果是吻合的。

這基本上就是整個Postback的整個程序執行的過程,現在我們對我們的Page作一些小的有趣的改動,來驗證一下:

ClIEnt端和Server端進行交互的途徑就是提交表單(Form Submitting),而我們現在有兩種方式來提交表單:通過<input type="submit">控件;通過調用Javascript:__doPostBack。基於這一點我們在Html中加了下面一段Javascript: 



<script type="text/Javascript">
    function postback()
    {
       
        __doPostBack(''Button1'','''');
    } 
   
    document.getElementById("Button2").onclick = postback;
    document.getElementById("Button3").onclick = postback; 
   </script>

我們override Button2和Button3的onclick event,把''Button1作為參數傳入__doPostBack方法,可以想象,現在無論Click那個Button,程序都將認為之Click Button1。有興趣的可以親自試試,無論Click那個Button,顯示的效果都將是下面的樣子: 


接下來我們取消上面的改動,在Server對Code作另一方面的嘗試。我們前面說過,Server接受到ClIEnt的Postback,對於事件的Web Control(或者Html Server Control),如果實現了System.Web.UI.IPostBackEventHandler接口,會調用Page的virtual方法:RaisePostbackEvent,我們現在來Override這個方法: 



protected override void RaisePostBackEvent(IPostBackEventHandler sourceControl, string eventArgument)
    {
        sourceControl = this.Button1;
        base.RaisePostBackEvent(sourceControl, eventArgument);
}

在上面的Code中,我們把sourceControl設為Button1,這樣無論在clIEnt端Click的那個Button,現在都將認為是對Button的Click。運行的結果和上面一樣。

通過上面的介紹,我們知道了Page的RaisePostBackEvent會調用Source Control的RaisePostBackEvent方法,這個方法是定義在IPostBackEventHandler接口中,很多Control都實現了這個方法,對於Button來說,這個方法是Virtual的,它可以被你Override,如果感興趣的話,可以自己寫一個Custom Button,並Override該方法,看看執行的情況,相信會使加深你對Postback的理解。


[EditorBrowsable(EditorBrowsableState.Advanced)]
protected virtual void RaisePostBackEvent(IPostBackEventHandler sourceControl, string eventArgument)
<script type="text/Javascript">
    function postback()
    {
       
        __doPostBack(''Button1'','''');
    } 
   
    document.getElementById("Button2").onclick = postback;
    document.getElementById("Button3").onclick = postback; 
   </script>

我們override Button2和Button3的onclick event,把''Button1作為參數傳入__doPostBack方法,可以想象,現在無論Click那個Button,程序都將認為之Click Button1。有興趣的可以親自試試,無論Click那個Button,顯示的效果都將是下面的樣子: 


接下來我們取消上面的改動,在Server對Code作另一方面的嘗試。我們前面說過,Server接受到ClIEnt的Postback,對於事件的Web Control(或者Html Server Control),如果實現了System.Web.UI.IPostBackEventHandler接口,會調用Page的virtual方法:RaisePostbackEvent,我們現在來Override這個方法: 



protected override void RaisePostBackEvent(IPostBackEventHandler sourceControl, string eventArgument)
 {
    sourceControl.RaisePostBackEvent(eventArgument);
}

我們可以看到該方法直接調用該sourceControl的RaisePostBackEvent,並傳入一個eventArgument參數,在這個例子中sourceControl就是__EVENTTARGET對應的Web Control:Button2,eventArgument就是__EVENTTARGET對應的值:一個空字符串。Button2的類型是System.Web.UI.WebControls.Button。我們來看看System.Web.UI.WebControls.Button中的RaisePostBackEvent方法是如何定義的:


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved