动态 UpdateProgress 控件






4.21/5 (9投票s)
在激活 UpdateProgress 控件时隐藏页面的一部分。
引言
我花了一周时间玩弄 AJAX Extensions 中包含的 UpdateProgress
控件。总的来说,这个控件本身用起来很不错,但有一点让我很头疼:我无法让这个控件在激活时隐藏页面上的某个区域。虽然这听起来微不足道,但在寻找页面设计中适合显示 UpdateProgress
并且对用户来说仍然直观的区域时,它变成了一个真正的麻烦,用户不知道发生了什么。
如果你已经为此挣扎过,你就会明白我说的意思。如果你还没有,我相信你最终也会的。这个控件将为你节省很多麻烦。
使用代码
ExtendedUpdateProgress
控件实际上非常容易使用。你可以在页面上像使用普通的 UpdateProgress
控件一样实现它,只需添加一些额外的属性。首先,请务必确保页面上有一个脚本管理器。
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
然后,在你的页面上实现 ExtendedUpdateProgress
控件(这是你可以下载的演示中的代码示例)。
<%@ Register Assembly="UpdateProgress"
Namespace="UpdateProgress.ExtendedUpdateProgress" TagPrefix="cc1" %>
<div id="test1Div">
<asp:Label ID="test1Label" runat="server" Text="Time will appear here">
</asp:Label>
</div>
<cc1:ExtendedUpdateProgress ID="ExtendedUpdateProgress1" runat="server"
AssociatedUpdatePanelID="test1UpdatePanel"
DisplayAfter="400" DivToHide="test1Div"
DynamicLayout="true" ImageToDisplay="Small">
</cc1:ExtendedUpdateProgress>
为了让这个控件工作,你必须指定一个 AssociatedUpdatePanelID
。新增的属性是 DivToHide
属性和 ImageToDisplay
属性。
在这个例子中,我想根据 ImageToDisplay
属性动态创建带有动画 GIF 的 UpdateProgress
控件的模板。如果你不想有相同的行为,可以删除这个属性以及控件中替换模板的代码。如果你这样做,你需要像普通 UpdateProgress
控件那样识别 ProgressTemplate
。而现在这样,ProgressTemplate
根本不需要定义。
DivToHide
属性接收一个 div
的 Id
,当 UpdateProgress
控件被触发时,该控件将隐藏与之关联的 div
。当 UpdateProgress
完成时,div
将重新显示。
理解代码
ExtendedUpdateProgress
控件首先会将所有合适的 JavaScript 渲染到页面,并使用其 divToHide
、AssociatedUpdatePanel
和 clientId
进行注册。由于页面上可能有一个以上的 UpdateProgress
控件,我们无法在生成的 JavaScript 中硬编码特定的 ID 和标签。因此,我们需要注册有效信息以便以后识别。SetUpdateProgressControl
函数是通过 Page.ClientScript
的 RegisterStartupScript
方法调用的。
var updateProgressControls
function UpdateProgress(updatePanelId, controlToHideId, updateProgressId)
{
this.ControlToHideId = controlToHideId;
this.UpdatePanelId = updatePanelId;
this.UpdateProgressId = updateProgressId;
}
function SetUpdateProgressControl(updatePanelId,
controlToHideId, updateProgressId)
{
/* Intantiate the updateProgressControls array if null */
if (updateProgressControls == null)
{
updateProgressControls = new Array();
}
/* if the control already exists replace it, else insert into the array*/
var controlIndex = 0;
for (var i=0, len=updateProgressControls.length; i<len; ++i )
{
if (updateProgressControls[i].UpdatePanelId == updatePanelId){
controlIndex = i;
break;}
controlIndex = controlIndex + 1;
}
updateProgressControls[controlIndex] =
new UpdateProgress(updatePanelId, controlToHideId, updateProgressId);
}
在将合适的信息注册到 JavaScript 后,PageRequestManager
的 BeginRequest
和 EndRequest
方法会被重写。
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(BeginRequestHandler);
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler);
当回发请求开始时,它会查看导致回发的 UpdatePanel
。如果它已在 ExtendedUpdateProgress
控件中注册,则会隐藏关联的 DivToHide
。特别说明一下,由于没有一个事件会在 UpdateProgress
控件激活时触发,我不得不使用 UpdateProgress
的 DisplayAfter
属性和 window.setTimeout
来延迟函数调用。我为超时增加了一个毫秒,因为 hideControl
会在隐藏关联的 div
之前检查 UpdateProgress
是否显示,这只是一个额外的预防措施。
function BeginRequestHandler(sender, args)
{
/* If the postback is called from with
a registered UpdatePanel, hide it's ControlToHide */
var updateControl = GetUpdateControl(sender._postBackSettings.panelID);
if (updateControl != null)
{
var postBackPanelControl = document.getElementById('postBackPanel');
postBackPanelControl.value = sender._postBackSettings.panelID;
var cbk = Function.createCallback(hideControl,
{ControlToHideId: updateControl.ControlToHideId,
UpdateProgressId: updateControl.UpdateProgressId});
window.setTimeout(cbk, " + (DisplayAfter + 1) + ");
}
}
function hideControl(e, context)
{
var controlId = (e.ControlToHideId == null)?
context.ControlToHideId:e.ControlToHideId;
var updateProgressId = (e.UpdateProgressId == null)?
context.UpdateProgressId:e.UpdateProgressId;
var divToHide = document.getElementById(controlId);
var progressDiv = document.getElementById(updateProgressId);
/* If the UpdateProgress control for this UpdatePanel
is visible, hide the associated div */
if (progressDiv.style.display != 'none')
{
divToHide.style.visibility = 'hidden';
divToHide.style.display = 'none';
}
}
当回发请求结束时,它会显示关联的 div
。
function EndRequestHandler(sender, args)
{
/* If the postback is called from with
a registered UpdatePanel, show it's ControlToHide */
var postBackPanelControl = document.getElementById('postBackPanel');
var panelId = (sender._postBackSettings.panelID == null)?
postBackPanelControl.value:sender._postBackSettings.panelID;
var updateControl = GetUpdateControl(panelId);
if (updateControl != null)
{
showControl(updateControl.ControlToHideId);
}
postBackPanelControl.value = '';
}
function showControl(controlId)
{
var divToHide = document.getElementById(controlId);
/* show the associated div */
divToHide.style.visibility = 'visible';
divToHide.style.display = 'block';
}
Begin
和 End
请求都使用一个名为 GetUpdateControl
的函数。这个函数的作用就是接收传入的 panelId
并找到该 Panel
的已注册 UpdateProgress
信息。
function GetUpdateControl(panelId)
{
if (panelId == null || panelId == '')
return null;
/* get the UpdatePanel ID */
var rawPanelId = panelId.split('|')[0];
var updatePanelId =
rawPanelId.substring(rawPanelId.lastIndexOf('$')+1, rawPanelId.length)
/* find the update panel in the updateProgressControls array and return */
for (var i=0, len=updateProgressControls.length; i<len; ++i )
{
if (updateProgressControls[i].UpdatePanelId == updatePanelId)
{
return updateProgressControls[i];
}
}
return null;
}
ExtendedUpdateProgress
控件背后的代码相当 extensive,但已得到充分记录,并且控件的实现极其简单。
关注点
我强烈建议你看看这个控件是如何工作的。页面上会渲染 extensive 的 JavaScript 来让这个控件工作并自我管理。它还需要能够允许页面上存在多个 UpdateProgress
控件。因此,渲染到页面的 JavaScript 需要能够适当地“注册”每个控件。
结论
请注意,目前该代码 **仅** 在 IE 中有效。我目前正在研究使其与 Firefox 和 Safari 兼容,并将在有更新时发布。更新:4 月 29 日。增加了对 Firefox 和 Safari 的支持。已在 Firefox 2.0 和 Safari 3.1.1 上测试。如果你想了解更改的描述,请随时提出。请享用代码,如果你有任何问题/评论/疑虑,请随时提出。
历史
- 2008 年 4 月 28 日 - 初始文章。
- 2008 年 4 月 29 日 - 上传了新的源代码和演示文件以支持 Firefox 和 Safari。
- 2008 年 4 月 30 日 - 有人要求提供更多描述。请查看上面的新“理解代码”部分。