65.9K
CodeProject 正在变化。 阅读更多。
Home

动态 UpdateProgress 控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.21/5 (9投票s)

2008 年 4 月 28 日

公共领域

4分钟阅读

viewsIcon

66395

downloadIcon

1344

在激活 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 属性接收一个 divId,当 UpdateProgress 控件被触发时,该控件将隐藏与之关联的 div。当 UpdateProgress 完成时,div 将重新显示。

理解代码

ExtendedUpdateProgress 控件首先会将所有合适的 JavaScript 渲染到页面,并使用其 divToHideAssociatedUpdatePanelclientId 进行注册。由于页面上可能有一个以上的 UpdateProgress 控件,我们无法在生成的 JavaScript 中硬编码特定的 ID 和标签。因此,我们需要注册有效信息以便以后识别。SetUpdateProgressControl 函数是通过 Page.ClientScriptRegisterStartupScript 方法调用的。

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 后,PageRequestManagerBeginRequestEndRequest 方法会被重写。

Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(BeginRequestHandler);
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler);

当回发请求开始时,它会查看导致回发的 UpdatePanel。如果它已在 ExtendedUpdateProgress 控件中注册,则会隐藏关联的 DivToHide。特别说明一下,由于没有一个事件会在 UpdateProgress 控件激活时触发,我不得不使用 UpdateProgressDisplayAfter 属性和 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';
}

BeginEnd 请求都使用一个名为 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 日 - 有人要求提供更多描述。请查看上面的新“理解代码”部分。
© . All rights reserved.