[ASP.NET]用Javascript觸發UpdatePanel的非同步postback
問題情況
在某個專案裡面,主要系統架構是使用UpdatePanel來做非同步的Postback,
需求是按了一個按鈕之後,要用window.open開啟一個新的子視窗,
新視窗資料處理完之後,關閉子視窗,並將母視窗相關資料都更新至最新的資料。
通常的寫法是window.close之後,接著執行母視窗的__doPostBack(),強迫postback。
然而碰到的問題情況是:
- 整頁都閃了;
- 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進來會有什麼樣不同的效果。
結論
__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/