为特定异步回发赋予优先级
更新:2007 年 11 月
默认情况下,当某个页同时生成多个异步回发时,最近生成的回发将优先。某些情况下,可以为特定的异步回发赋予优先级并取消其他回发。
在本教程中,您将控制要优先的回发。通过为 PageRequestManager 类的 initializeRequest 事件创建一个事件处理程序,可以做到这一点。有关在 PageRequestManager 类中引发的事件序列的信息,请参见处理 PageRequestManager 事件。
先决条件
若要在您自己的开发环境中实现这些过程,您需要:
Microsoft Visual Studio 2005 或 Microsoft Visual Web Developer 速成版。
一个支持 AJAX 的 ASP.NET 网站。
创建用于为特定回发元素赋予优先级的脚本
首先,创建用于管理浏览器中的异步回发的 ECMAScript (JavaScript) 代码。
创建用于为特定回发元素赋予优先级的脚本
在 ASP.NET 网站中,添加 JScript 文件并将其命名为 PostbackPrecedence.js。
向文件中添加以下脚本:
Sys.Application.add_load(ApplicationLoadHandler) function ApplicationLoadHandler(sender, args) { if (!Sys.WebForms.PageRequestManager.getInstance().get_isInAsyncPostBack()) { Sys.WebForms.PageRequestManager.getInstance().add_initializeRequest(InitializeRequest); } } var divElem = 'AlertDiv'; var messageElem = 'AlertMessage'; var exclusivePostBackElement = 'Button1'; var lastPostBackElement; function InitializeRequest(sender, args) { var prm = Sys.WebForms.PageRequestManager.getInstance(); if (prm.get_isInAsyncPostBack() && args.get_postBackElement().id === exclusivePostBackElement) { if (lastPostBackElement === exclusivePostBackElement) { args.set_cancel(true); ActivateAlertDiv('visible', 'A previous postback is still executing. The new postback has been canceled.'); setTimeout("ActivateAlertDiv('hidden','')", 1500); } else if (lastPostBackElement !== exclusivePostBackElement) { prm.abortPostBack(); } } else if (prm.get_isInAsyncPostBack() && args.get_postBackElement().id !== exclusivePostBackElement) { if (lastPostBackElement === exclusivePostBackElement) { args.set_cancel(true); ActivateAlertDiv('visible', 'A previous postback is still executing. The new postback has been canceled.'); setTimeout("ActivateAlertDiv('hidden','')", 1500); } } lastPostBackElement = args.get_postBackElement().id; } function ActivateAlertDiv(visString, msg) { var adiv = $get(divElem); var aspan = $get(messageElem); adiv.style.visibility = visString; aspan.innerHTML = msg; } if(typeof(Sys) !== "undefined") Sys.Application.notifyScriptLoaded();
Sys.Application.add_load(ApplicationLoadHandler) function ApplicationLoadHandler(sender, args) { if (!Sys.WebForms.PageRequestManager.getInstance().get_isInAsyncPostBack()) { Sys.WebForms.PageRequestManager.getInstance().add_initializeRequest(InitializeRequest); } } var divElem = 'AlertDiv'; var messageElem = 'AlertMessage'; var exclusivePostBackElement = 'Button1'; var lastPostBackElement; function InitializeRequest(sender, args) { var prm = Sys.WebForms.PageRequestManager.getInstance(); if (prm.get_isInAsyncPostBack() && args.get_postBackElement().id === exclusivePostBackElement) { if (lastPostBackElement === exclusivePostBackElement) { args.set_cancel(true); ActivateAlertDiv('visible', 'A previous postback is still executing. The new postback has been canceled.'); setTimeout("ActivateAlertDiv('hidden','')", 1500); } else if (lastPostBackElement !== exclusivePostBackElement) { prm.abortPostBack(); } } else if (prm.get_isInAsyncPostBack() && args.get_postBackElement().id !== exclusivePostBackElement) { if (lastPostBackElement === exclusivePostBackElement) { args.set_cancel(true); ActivateAlertDiv('visible', 'A previous postback is still executing. The new postback has been canceled.'); setTimeout("ActivateAlertDiv('hidden','')", 1500); } } lastPostBackElement = args.get_postBackElement().id; } function ActivateAlertDiv(visString, msg) { var adiv = $get(divElem); var aspan = $get(messageElem); adiv.style.visibility = visString; aspan.innerHTML = msg; } if(typeof(Sys) !== "undefined") Sys.Application.notifyScriptLoaded();
该脚本执行下列任务:
定义 Sys.Application 类的 load 事件的处理程序。该处理程序随后为 PageRequestManager 类的 initializeRequest 事件注册一个名为 InitializeRequest 的处理程序。
定义 InitializeRequest 处理程序以检查当前是否正在执行一个异步回发,并确定导致该回发的元素的名称。如果导致回发的元素是一个已指定的独占式回发元素(即一个应优先的元素),则通过设置 InitializeRequestEventArgs 类的 cancel 属性取消新的回发。
定义一个 ActivateAlertDiv 函数,以便在页面上切换 <div> 元素的可见性以显示消息。
对 UpdatePanel 控件使用脚本
在此过程中,将使用您在页中创建的脚本。该页包含一个按钮,其回发优先级高于页上的另一个按钮。
创建页以确保来自一个回发的回发优先
创建新的单文件 ASP.NET 网页并切换到“设计”视图。
在工具箱的**“AJAX Extensions”**选项卡中,双击 ScriptManager 控件以将其添加到页面中。
双击 UpdatePanel 控件两次,以将该控件的两个实例添加到页面中。
在每个 UpdatePanel 控件中,从工具箱的**“标准”**选项卡中添加 Label 控件和 Button 控件。
将两个面板中的 Label 控件的 Text 值都设置为“最初呈现的面板”。
双击每个 Button 控件,以便为每个按钮的 Click 事件添加处理程序。
在 Click 处理程序中添加下列代码,人为地制造一段延迟,然后在导致回发的面板中显示当前时间:
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) System.Threading.Thread.Sleep(4000) Label1.Text = "Last update from server " & DateTime.Now.ToString() End Sub Protected Sub Button2_Click(ByVal sender As Object, ByVal e As EventArgs) System.Threading.Thread.Sleep(1000) Label2.Text = "Last update from server " & DateTime.Now.ToString() End Sub
protected void Button1_Click(object sender, EventArgs e) { System.Threading.Thread.Sleep(4000); Label1.Text = "Last update from server " + DateTime.Now.ToString(); } protected void Button2_Click(object sender, EventArgs e) { System.Threading.Thread.Sleep(1000); Label2.Text = "Last update from server " + DateTime.Now.ToString(); }
说明: 出于本教程的需要,Click 事件的处理程序有意引入了延迟。在实际应用中,您不会引入延迟。相反,延迟是由服务器通信量或需要花很长时间处理的服务器代码造成的,例如长时间运行的数据库查询。
切换至“源”视图,然后在页的 <style> 元素中添加以下 <style> 块:
<style type="text/css"> body { font-family: Tahoma; } #UpdatePanel1, #UpdatePanel2 { width: 400px; height: 100px; border: solid 1px gray; } div.MessageStyle { background-color: #FFC080; top: 95%; left: 1%; height: 20px; width: 600px; position: absolute; visibility: hidden; } </style>
<style type="text/css"> body { font-family: Tahoma; } #UpdatePanel1, #UpdatePanel2 { width: 400px; height: 100px; border: solid 1px gray; } div.MessageStyle { background-color: #FFC080; top: 95%; left: 1%; height: 20px; width: 600px; position: absolute; visibility: hidden; } </style>
样式规则定义由 UpdatePanel 控件呈现的 <div> 元素的大小,并定义当取消回发时用于提醒用户的 <div> 元素的大小。
在页上的 <form> 元素的内部添加下列标记:
<div id="AlertDiv" class="MessageStyle"> <span id="AlertMessage"></span> </div>
<div id="AlertDiv" class="MessageStyle"> <span id="AlertMessage"></span> </div>
该标记定义一个 <div> 元素,该元素将在取消异步回发时(原因是另一个异步回发正在进行中)显示消息。
切换到“设计”视图。
在第一个 UpdatePanel 控件内单击,然后从工具箱中的**“AJAX Extensions”**选项卡添加一个 UpdateProgress 控件。
在 UpdateProgress 控件内单击,然后键入“面板 1 正在更新…”。
这将设置 ProgressTemplate 属性。
选择 UpdateProgress 控件,然后在“属性”窗口中,将 AssociatedUpdatePanelID 属性设置为“UpdatePanel1”。
设计器中的页将与下图类似:
在第二个 UpdatePanel 控件内单击,添加另一个 UpdateProgress 控件。
在 UpdateProgress 控件内单击,然后键入“面板 2 正在更新…”。
这将设置 ProgressTemplate 属性。
选择 UpdateProgress 控件,然后在“属性”窗口中将 AssociatedUpdatePanelID 属性设置为“UpdatePanel2”。
设计器中的页将与下图类似:
选择 ScriptManager 控件。
在“属性”窗口中,选择**“脚本”属性,再单击省略号 (…) 按钮以显示“ScriptReference 集合编辑器”**对话框。
单击**“添加”**以添加脚本引用。
将脚本引用的**“路径”**属性设置为 PostbackPrecedence.js,该文件是以前创建的 JavaScript 文件。
使用 ScriptManager 的 Scripts 集合添加脚本引用可确保在 Microsoft AJAX Library 加载之后加载相应的脚本。
单击**“确定”关闭“ScriptReference 集合编辑器”**对话框。
保存更改,然后按 Ctrl+F5 在浏览器中查看页面。
单击第一个面板中的按钮,然后单击第二个面板中的按钮。
将显示一条消息,指示新的回发已被取消。第一个面板中的按钮必须在启动新的回发之前完成。脚本文件提供用于强制执行这一行为的逻辑。
单击第二个面板中的按钮,然后单击第一个面板中的按钮。
第二个面板中的按钮没有优先,因为在脚本文件中未对其进行相应的编码来做到这一点。因此,不显示任何警告消息,并且新的回发由第一个面板中的按钮启动。这是异步回发的默认行为,即最近生成的回发优先。
<%@ Page Language="VB" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script runat="server"> Protected Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) System.Threading.Thread.Sleep(4000) Label1.Text = "Last update from server " & DateTime.Now.ToString() End Sub Protected Sub Button2_Click(ByVal sender As Object, ByVal e As EventArgs) System.Threading.Thread.Sleep(1000) Label2.Text = "Last update from server " & DateTime.Now.ToString() End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml"> <head id="Head1" runat="server"> <title>Postback Precedence Example</title> <style type="text/css"> body { font-family: Tahoma; } #UpdatePanel1, #UpdatePanel2 { width: 400px; height: 100px; border: solid 1px gray; } div.MessageStyle { background-color: #FFC080; top: 95%; left: 1%; height: 20px; width: 600px; position: absolute; visibility: hidden; } </style> </head> <body> <form id="form1" runat="server"> <div> <asp:ScriptManager ID="ScriptManager1" runat="server"> <Scripts> <asp:ScriptReference Path="PostBackPrecedence.js" /> </Scripts> </asp:ScriptManager> <asp:UpdatePanel ID="UpdatePanel1" UpdateMode="Conditional" runat="Server" > <ContentTemplate> <strong>UpdatePanel 1</strong><br /> This postback takes precedence.<br /> <asp:Label ID="Label1" runat="server">Panel initially rendered.</asp:Label><br /> <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" /> <asp:UpdateProgress ID="UpdateProgress1" runat="server" AssociatedUpdatePanelID="UpdatePanel1"> <ProgressTemplate> Panel1 updating... </ProgressTemplate> </asp:UpdateProgress> </ContentTemplate> </asp:UpdatePanel> <asp:UpdatePanel ID="UpdatePanel2" UpdateMode="Conditional" runat="Server" > <ContentTemplate> <strong>UpdatePanel 2</strong><br /> <asp:Label ID="Label2" runat="server">Panel initially rendered.</asp:Label><br /> <asp:Button ID="Button2" runat="server" Text="Button" OnClick="Button2_Click" /> <asp:UpdateProgress ID="UpdateProgress2" runat="server" AssociatedUpdatePanelID="UpdatePanel2"> <ProgressTemplate> Panel2 updating... </ProgressTemplate> </asp:UpdateProgress> </ContentTemplate> </asp:UpdatePanel> <div id="AlertDiv" class="MessageStyle"> <span id="AlertMessage"></span> </div> </div> </form> </body> </html>
<%@ Page Language="C#" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script runat="server"> protected void Button1_Click(object sender, EventArgs e) { System.Threading.Thread.Sleep(4000); Label1.Text = "Last update from server " + DateTime.Now.ToString(); } protected void Button2_Click(object sender, EventArgs e) { System.Threading.Thread.Sleep(1000); Label2.Text = "Last update from server " + DateTime.Now.ToString(); } </script> <html xmlns="http://www.w3.org/1999/xhtml"> <head id="Head1" runat="server"> <title>Postback Precedence Example</title> <style type="text/css"> body { font-family: Tahoma; } #UpdatePanel1, #UpdatePanel2 { width: 400px; height: 100px; border: solid 1px gray; } div.MessageStyle { background-color: #FFC080; top: 95%; left: 1%; height: 20px; width: 600px; position: absolute; visibility: hidden; } </style> </head> <body> <form id="form1" runat="server"> <div> <asp:ScriptManager ID="ScriptManager1" runat="server"> <Scripts> <asp:ScriptReference Path="PostBackPrecedence.js" /> </Scripts> </asp:ScriptManager> <asp:UpdatePanel ID="UpdatePanel1" UpdateMode="Conditional" runat="Server" > <ContentTemplate> <strong>UpdatePanel 1</strong><br /> This postback takes precedence.<br /> <asp:Label ID="Label1" runat="server">Panel initially rendered.</asp:Label><br /> <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" /> <asp:UpdateProgress ID="UpdateProgress1" runat="server" AssociatedUpdatePanelID="UpdatePanel1"> <ProgressTemplate> Panel1 updating... </ProgressTemplate> </asp:UpdateProgress> </ContentTemplate> </asp:UpdatePanel> <asp:UpdatePanel ID="UpdatePanel2" UpdateMode="Conditional" runat="Server" > <ContentTemplate> <strong>UpdatePanel 2</strong><br /> <asp:Label ID="Label2" runat="server">Panel initially rendered.</asp:Label><br /> <asp:Button ID="Button2" runat="server" Text="Button" OnClick="Button2_Click" /> <asp:UpdateProgress ID="UpdateProgress2" runat="server" AssociatedUpdatePanelID="UpdatePanel2"> <ProgressTemplate> Panel2 updating... </ProgressTemplate> </asp:UpdateProgress> </ContentTemplate> </asp:UpdatePanel> <div id="AlertDiv" class="MessageStyle"> <span id="AlertMessage"></span> </div> </div> </form> </body> </html>
回顾
本教程演示了如何使某个特定的异步回发在另一个异步回发启动之前优先完成处理。强制执行这一行为的逻辑位于一个 JavaScript 文件中,该文件作为页的脚本引用而包含在网站文件中。可以自定义脚本,以便所有的当前异步回发必须在任何新的异步回发启动之前完成。但是,您在指定要优先的回发时应仔细考虑您的设计。