[ASP.NET]用Javascript觸發UpdatePanel的非同步postback

  • 27908
  • 0

[ASP.NET]用Javascript觸發UpdatePanel的非同步postback

問題情況

在某個專案裡面,主要系統架構是使用UpdatePanel來做非同步的Postback,
需求是按了一個按鈕之後,要用window.open開啟一個新的子視窗,
新視窗資料處理完之後,關閉子視窗,並將母視窗相關資料都更新至最新的資料。
通常的寫法是window.close之後,接著執行母視窗的__doPostBack(),強迫postback。
然而碰到的問題情況是:

  1. 整頁都閃了;
  2. scroll bar回到頁面最上面;

 

Solution

其實小朋友自己也有自己的solution了,
他在UpdatePanel裡面放了一個按鈕,回來母視窗時去呼叫這個button.click(),
由於預設在UpdatePanel裡面的Control,觸發的postback事件都會被ScriptManager攔截下來,轉發成AsyncPostback,
所以,這樣的解法也是可行,只是這樣子會額外觸發Button的Click事件,可能會導致多跑了不想跑的CODE,
例如該按鈕如果有新增的操作,則多新增了一筆。
而且這樣的設計邏輯是頗詭異的,「當子視窗關閉時,用js去按母視窗的按鈕,是為了AsyncPostback」?

為什麼呼叫放在UpdatePanel裡面的Button就可以觸發AsyncPostback,而呼叫__doPostBack()卻整頁postback呢?
(內心OS:一定是Trigger搞的鬼啊…)
既然Button可以,沒道理__doPostBack()不行啊…button的postback還不是一樣呼叫__doPostBack()在做事嗎?
只是攔截觸發postback的Control,在Control event時在觸發委派的方法,我印象中是這樣。

後來突然想到,一定是__doPostBack()用錯了…因為__doPostBack(eventTarget, eventArgument),如果參數裡面給空值,預設是page,當然會整頁postback。
只要__doPostBack(eventTarget, eventArgument)的eventTarget給button的clientID,應該就跟呼叫button.click()一樣了。
這時候突發奇想,eventTarget給Button會跑Button click事件委派的方法,給TextBox會跑TextChanged,給DropDownList會跑SelectedIndexChanged,
啊我就只是要非同步重Bind資料而已…不想多跑任何的Control事件來影響我的結果,
後來發現,把UpdatePanel裡面的Label丟進去eventTarget也有一樣的效果。

 

範例

  • 當我按下在UpdatePanel裡的Button2時,就如同預期般呈現了AsyncPostBack的效果,Scrollbar也沒有跑掉。
  • 當我按下在UpdatePanel裡的Button1時,就如同預期般呈現了整頁PostBack的效果,Scrollbar跑到了最上面。
  • 當我要用javascript來觸發AsyncPostBack時,我希望點了html button,也就是Button3時,可以AsyncPostBack,Scrollbar仍停留在原位置。

aspx

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>未命名頁面</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
            <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
            <asp:Label ID="Label1" runat="server" Text="123"></asp:Label>   
            <asp:Button ID="Button2" runat="server" Text="我在updatepanel裡面,所以不會閃" OnClick="Button2_Click" />    
        </ContentTemplate>                                    
            <Triggers>
                <asp:AsyncPostBackTrigger ControlID="TextBox1" />
            </Triggers>
        </asp:UpdatePanel>        
        <input id="Button3" onclick="__doPostBack('Label1','');" type="button" value="我是js button,測試非同步postback" />
        <asp:Button ID="Button1" runat="server" Text="我在updatepanel外,所以會閃" />
    </div>
    </form>
</body>
</html>

這邊為了方便檢查Scrollbar位置有沒跑掉,所以寫了個loop來長資料。

.cs

{
    protected void Page_Load(object sender, EventArgs e)
    {
        int postbackTimes = 0;
        
        if (!IsPostBack)
        {
            this.ViewState["postbackTimes"] = postbackTimes;
            string a = string.Empty;
            for (int i = 0; i < 80; i++)
            {
                a += i + "<br>";
            }
            this.Label1.Text = a;
        }
        else
        {
            postbackTimes = (int)this.ViewState["postbackTimes"] + 1;
            this.TextBox1.Text = "postback"+postbackTimes.ToString()+"次了";
            this.ViewState["postbackTimes"] = postbackTimes;
        }
    }
    protected void Button2_Click(object sender, EventArgs e)
    {

    }
}

 

可以在Page_Load()與Button2_Click()去設定中斷點,看js裡__doPostBack的eventTarget,丟不同的id進來會有什麼樣不同的效果。

2009-08-18_115058

 

結論

__dopostback()的eventTarget如果是在UpdatePanel的範圍裡面,可以觸發AsyncPostBack,且會觸發eventTarget預設的postback事件。
Sample Code:AsyncPostbackByJs.rar

註:如果想知道現在觸發__doPostBack的參數為何,可以用Page.Request.Form取得

 Dim a As String = Me.Page.Request.Form("__EVENTTARGET")  
 Dim c As String = Me.Page.Request.Form("__EVENTARGUMENT")

註2:eventTarget不知道丟啥,就丟UpdatePanel的ID吧...合情合理又沒啥後遺症


blog 與課程更新內容,請前往新站位置:http://tdd.best/