var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_initializeRequest(function(){
alert("在開始處理異步請求之前引發。可以使用此事件取消回發");
});
prm.add_beginRequest(function(){
alert("在開始處理異步回發、將回發發送到服務器之前引發。可以使用此事件來設置請求標頭,或開始一個動畫以指示正在處理頁面");
});
prm.add_pageLoading(function(){
alert("在收到服務器對異步回發的響應之後、頁上任何內容更新之前引發。可以使用此事件爲更新的內容提供自定義轉換效果");
});
prm.add_pageLoaded(function(){
alert("在因同步回發或異步回發而刷新頁上的所有內容之後引發。可以使用此事件爲更新的內容提供自定義轉換效果");
});
prm.add_endRequest(function(){
alert("在異步回發完成,並且控制權返回到瀏覽器之後引發。可以使用此事件向用戶提供通知或將錯誤記錄到日誌");
});
*********************************************************************************************************************
ScriptManager和UpdatePanel兩個控件已經能夠實現了客戶端與服務器端的異步通信了。要想對異步操作進一步控制的話,那我們還得進一步研究PageReqeustManager類。
PageRequestManager類是客戶端的類,用於協調ScriptManager和UpdatePanel控件,管理頁面上的異步更新操作。通過PageRequestManager客戶端的實例我們可以深入到在客戶端頁面生命週期中,更細緻地操作客戶端的頁面。
一、PageRequestManager實例:
要想在客戶端獲得PageRequestManager實例,頁面上必須擁有一人ScriptManager控件,並且ScriptManager控件的EnablePartialRendering屬性必須設爲True。
只要頁面上內含一個EnablePartialRendering屬性爲True的ScriptManager控件,該頁面就會自動創建一個PageRequestManager實例。程序員不需要自行創建PageRequestManager實例,直接取來用即可。
取得PageRequestManager實例的代碼:
var prm = Sys.WebForms.PageRequestManager.getInstance();
屬性prm.get_isInAsyncPostBack():判斷一個異步回送是否正在進行中。
方法prm.abortPostBack():把一個正在執行中的異步回送取消。
二、客戶端頁面的生命週期:
PageRequestManager類的優勢就是能夠讓程序員深入至客戶端頁面的生命週期中去。所以要想充分發揮PageRequestManager類的功能,那首先要了解異步頁的生命週期。
1、initializeRequest:
觸發時機:當一個異步請求的回送被初始化之前引發。
添加事件處理代碼:Sys.WebForms.PageRequestManager.getInstance().add_initializeRequest(initFunc);
移除事件處理代碼:Sys.WebForms.PageRequestManager.getInstance().remove_initializeRequest(initFunc);
initFunc是該頁面初始化之前要執行的客戶端方法。該方法的聲明爲:
function initFunc(sender,args)
{
//args的數據類型是:InitializeRequestEventArgs類型。
//args.get_postBackElement():取得初始化異步回送的元素對象。
//args.get_postBackElement().id取得初始化異步回送的元素對象的id號
//args.get_postBackElement().value取得初始化異步回送的元素對象的value值
//args.set_cancel(bool):取消初始化異步回送,即丟棄該異步回送。
}
如果異步處理的過程比較慢,在異步處理的過程中再次發出同樣的請求的話,那後者的異步處理請求會取消掉前一步未處理完的請求。這就是默認的異步請求優先級--“後者優先”。
我們通常回利用initailizeRequest事件來取消一個異步回送(正在進行的回送和將要初始化的回送)。
2、beginRequest:
觸發時機:在異步請求初始化完成,且向服務器提出請求之前引發。
添加事件處理代碼:Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(beginFunc);
移除事件處理代碼:Sys.WebForms.PageRequestManager.getInstance().remove_beginRequest(beginFunc);
beginFunc是向服務器提出請求之前要執行的客戶端方法。該方法的聲明爲:
function beginFunc(sender,args)
{
//args的數據類型是:BeginRequestEventArgs類型。
//args.get_postBackElement():取得初始化異步回送的元素對象。
}
我們通常在beginRequest事件中設置一個標頭,或是啓始化一個動化告知用戶正在進行請求處理。
3、pageLoading:
觸發時機:異步回送已經被服務器接收並響應,但還沒有對頁面進行任何更新之前引發
添加事件處理代碼:Sys.WebForms.PageRequestManager.getInstance().add_pageLoading(loadingFunc);
移除事件處理代碼:Sys.WebForms.PageRequestManager.getInstance().remove_pageLoading(loadingFunc);
loadingFunc是頁面更新之前要執行的客戶端方法。該方法的聲明爲:
function loadingFunc(sender,args)
{
//args的數據類型是:PageLoadingEventArgs類型。
//args代表內容將要被更新或刪除的UpdatePanel控件的<div>。
//var arr = args.get_panelsDeleting(); 取得將被刪除的各個UpdatePanel控件的<div>
//var arr = args.get_panelsUpdating();取得將被更新的各個UpdatePanel控件的<div>
}
4、pageLoaded:
觸發時機:回送完成頁面區域被更新之後引發。
添加事件處理代碼:Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(loadedFunc);
移除事件處理代碼:Sys.WebForms.PageRequestManager.getInstance().remove_pageLoaded(loadedFunc);
loadedFunc是頁面更新後要執行的客戶端方法。該方法的聲明爲:
function loadedFunc(sender,args)
{
//args的數據類型是:PageLoadedEventArgs類型
//args代表更新的或創建的UpdatePanel控件的<div>
//var arr = args.get_panelsUpdated();取得被更新的各個UpdatePanel控件的<div>
//var arr = args.get_panelsCreated();取得新創建的各個UpdatePanel控件的<div>
}
5、endRequest:
觸發時機:回送請求處理完畢後,就會引發endRequest事件。
添加事件處理代碼:Sys.WebForms.PageRequestManager.getInstance().add_endRequest(endFunc);
移除事件處理代碼:Sys.WebForms.PageRequestManager.getInstance().remove_endRequest(endFunc);
endFunc是頁面請求完成後執行的客戶端方法。該方法的聲明爲:
function endRequest(sender,args)
{
//args的數據類型是:EndRequestEventArgs類型
//var err = args.get_error():判斷是否發生錯誤,並取得錯誤對象。
//var em = args.get_error().message:取得錯誤的出錯信息。
//args.set_errorHandled(true):設置錯誤已被處理。
//var gm = args.get_errorHandled():判斷錯誤是否被處理。
//異步請求發生異常後,如果程序員不在客戶端捕獲處理的話,PageRequestManager對象會將其以對話框的形式彈出異常的信息。如果程序員想自己編寫錯誤處理代碼,而不交由PageRequestManager對象處理的話。那程序員可以通過args.get_error().message屬性取得錯誤信息,然後編寫異常處理代碼,最後記得執行args.set_errorHandled(true)。這樣就阻止異常繼續回返給PageRequestManager對象。具體使用在後面將詳細說明。
}
三、案例:
1、異步回送的優先級-後者的優先級高於前者:
如果處理異步回送用的時間很長的話,那麼在處理第一個回送的過程中,客戶端又產生第二次異步回送的話話,那後引發的回送回取消先引發的回送。
頁面上有兩個異步按鈕,產生異步回送,爲了拉長服務器端處理回送的時間,我分別在兩個按鈕的服務器click事件中使用線程休眠了10秒和5秒,然後再向lblInfo標籤中輸入處理結果。
<asp:Button ID="btnLong" runat="server" Text="10秒後產生響應" OnClick="btnLong_Click" />
<asp:Button ID="btnShort" runat="server" Text="5秒後產生響應" OnClick="btnShort_Click" />
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:Label ID="lblInfo" runat="server" BackColor="#C0C0FF" Width="100%"></asp:Label>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="btnLong" EventName="Click" />
<asp:AsyncPostBackTrigger ControlID="btnShort" EventName="Click" />
</Triggers>
</asp:UpdatePanel>
爲了讓大家看清楚後一步引發會取消掉前一步的引發,我在PageRequestManager對象中加入了beginRequest事件處理代碼,在發送請求前在頁面上顯示請求發送者 。
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_beginRequest(beginR);
function beginR(sender,args)
{
var d = $get("lblInfo");
var t = args.get_postBackElement().value;
d.innerHTML = "正在處理同"+t+"引發的回送";
}
服務器端的代碼:
protected void Page_Load(object sender, EventArgs e)
{
ScriptManager1.RegisterAsyncPostBackControl(this.btnLong);
ScriptManager1.RegisterAsyncPostBackControl(this.btnShort);
}
protected void btnLong_Click(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(10000);
lblInfo.Text = ((Button)sender).Text + "產生的響應";
}
protected void btnShort_Click(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(5000);
lblInfo.Text = ((Button)sender).Text + "產生的響應";
}
效果:當點擊"10秒後產生響應"按鈕的時候,在lblInfo中會顯示"正在處理同10秒後產生響應引發的回送",如果此時你再點擊"5秒後產生響應"按鈕的時候,lblInfo的顯示會變成"正在處理同5秒後產生響應引發的回送"。此時第一次引發的回送回被取消,等待5後頁面上會顯示出"5秒後產生響應產生的響應",並不出現第一次回送的服務器響應。
2、取消異步回送:
取消異步回送分兩種:
a. 取消自在執行的異步回送-通過調用PageRequestManager對象的abortPostback()方法來取消。
b. 取消新產生的異點回送-通過設置InitializeRequestEventArgs對象的cancel屬性爲true來取消。
下面是一個查詢汽車信息的界面,爲了拉長服務器的處理時間,我在查詢按鈕中加入了6秒中的休眠時間。
在點擊查詢的時候,爲了不讓用戶乾等,我加入了一個<div>,提示用戶請求正在處理中,在<div>中加入一個"取消"按鈕,當用戶點擊 "取消"按鈕的時候,可以中止服務器端的異步處理。
等到服務器處理完畢異步請求後顯示下面的界面
如果在服務器未處理完異步請求時,用戶再點擊"查詢"按鈕,做到防止後引發的回送沖掉第一次引發的回送,並在界面中加入提示信息。
界面設計:
HTML代碼如下:
<asp:ScriptManager ID="ScriptManager1" runat="server" AsyncPostBackErrorMessage="這是一個自定義的小異常">
</asp:ScriptManager>
<asp:DropDownList ID="ddl" runat="server" DataSourceID="SqlDataSource1" DataTextField="prod_name"
DataValueField="prod_code" Width="194px">
</asp:DropDownList>
<asp:Button ID="Button1" runat="server" Text="查詢" OnClick="Button1_Click" />
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:mydbConnectionString %>"
SelectCommand="SELECT [prod_code], [prod_name] FROM [productor]"></asp:SqlDataSource>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<div id="divInfo" style="background-color: #ff99ff; display: none;">
<asp:Button ID="btnCancel" runat="server" Text="取消" /></div>
<br />
<asp:GridView ID="list" runat="server" Width="100%" DataSourceID="SqlDataSource2">
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSource2" runat="server" >
</asp:SqlDataSource>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="Button1" EventName="Click" />
</Triggers>
</asp:UpdatePanel>
CS代碼如下:
protected void Page_Load(object sender, EventArgs e)
{
ScriptManager1.RegisterAsyncPostBackControl(this.Button1);
}
protected void Button1_Click(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(6000);
string str = WebConfigurationManager.ConnectionStrings["mydbConnectionString"].ToString();
SqlDataSource2.ConnectionString = str;
SqlDataSource2.SelectCommand = "select car.ids,car.name,car.price,brand.brand_name,prod_code from car join brand on car.brand=brand_code where prod_code=@p";
SqlDataSource2.SelectParameters.Clear();
SqlDataSource2.SelectParameters.Add("p",ddl.SelectedValue);
SqlDataSource2.Select(DataSourceSelectArguments.Empty);
}
客戶端JS代碼的實現:
var prm = Sys.WebForms.PageRequestManager.getInstance(); //取得PageRequestManager對象的實例
prm.add_initializeRequest(init); //添加對象初始化事件處理程序
function init(sender,args) //事件處理程序
{
//如果在異步處理過程中,點擊了"取消"按鈕的話,就中止正在處理的異步處理 。
if(prm.get_isInAsyncPostBack() && args.get_postBackElement().id=="btnCancel")
{
prm.abortPostBack(); //中止異步處理
}
//如果在異步處理過程中,又點擊了一次"查詢"按鈕的話,就取消新的請求。
else if(prm.get_isInAsyncPostBack() && args.get_postBackElement().id=="Button1")
{
args.set_cancel(true); //取消新的請求
var d = $get("divInfo");
d.style.display = "";
d.innerHTML += "<br>仍然正在請求中,請稍候";
}
//如果沒有異步處理正在執行,用戶點擊了"查詢"按鈕的話,就顯示"正在請求中,請稍候"
else if(!prm.get_isInAsyncPostBack() && args.get_postBackElement().id=="Button1")
{
var d = $get("divInfo");
d.style.display = "";
d.innerHTML += "<br>正在請求中,請稍候";
}
}
3、異步請求自定義的錯誤處理。
在異步請求處理中如果產生錯誤,系統默認會彈一個瀏覽的對話框,告訴用戶的出錯信息。有時候我們並不想用這種默認的異常處理界面,那如何處理呢?
實現步驟:
a、編寫ScriptManager對象的服務器端事件ScriptManager1_AsyncPostBackError代碼,把捕獲的錯誤信息賦給ScriptManager對象的AsyncPostBackErrorMessage屬性。
b、添加PageRequestManager對象的endRequest事件處理程序。在處理程序中用args.get_error().message取出運行中的錯誤信息。然後在指定的<Div >中把錯誤信息顯示出來。
c、用set_errorHandled(true)把錯誤對象標記爲已處理,防止錯誤對象繼續冒泡給瀏覽器。
界面:
HTML代碼:
<asp:ScriptManager ID="ScriptManager1" runat="server" OnAsyncPostBackError="ScriptManager1_AsyncPostBackError">
</asp:ScriptManager>
<br />
<asp:Button ID="btnOK" runat="server" OnClick="btnOK_Click" Text="成功送出" />
<asp:Button ID="btnError" runat="server" OnClick="btnError_Click" Text="送出失敗" /></div>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:Label ID="lblInfo" runat="server" BackColor="#C0C0FF" Width="100%"></asp:Label>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="btnError" EventName="Click" />
<asp:AsyncPostBackTrigger ControlID="btnOK" EventName="Click" />
</Triggers>
</asp:UpdatePanel>
CS代碼:
protected void Page_Load(object sender, EventArgs e)
{
ScriptManager1.RegisterAsyncPostBackControl(btnOK);
ScriptManager1.RegisterAsyncPostBackControl(btnError);
}
protected void btnOK_Click(object sender, EventArgs e)
{
lblInfo.Text = "異步回送成功";
}
protected void btnError_Click(object sender, EventArgs e)
{
Exception ex = new Exception("這是一個自定義的用戶異常信息");
throw ex;
}
protected void ScriptManager1_AsyncPostBackError(object sender, AsyncPostBackErrorEventArgs e)
{
ScriptManager1.AsyncPostBackErrorMessage += e.Exception.Message;
}
客戶端JS代碼:
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(endfunc);
function endfunc(sender,args)
{
if(args.get_error() != null)
{
var em = args.get_error().message;
args.set_errorHandled(true);
$get("lblInfo").innerHTML = em;
}
}