Hello World
Spiga

Tip:Modal UpdateProgress的轻量级解决方案

2007-03-22 08:50 by 老赵, 7623 visits

又被问了这样一个问题:UpdateProgress如何像ModalPopupExtender那样的效果呢?类似的问题有:如何在UpdatePanel里使用ModalPopupExtender呢?

以前被问到这个问题的时候,我一般是这么回复的:UpdateProgress里可以放置任意HTML,您只要保证UpdateProgress里的HTML能够是Modal的就可以了,并不需要用到ModalPopupExtender。

说实话,我的确不知道如何将ModalPopupExtender用于UpdateProgress之上。因为ModalPopupBehavior需要一个Element作为触发器,用于弹出ModalDialog。UpdateProgress并没有这么一个触发器,虽然我们可以调用Behvaior的hide和show方法来控制ModalDialog,可是UpdateProgress又没有任何事件等等,我们又该在什么时候调用这些方法呢?当然,我们可以改写一下UpdateProgress,为它放出一些事件,这样我们就可以响应这些事件来进行一些操作了。不过这种做法“trick”的成分感觉会大于“solution”,我更希望通过一种“正统”的方式来解决这个问题。

其实我之前的回答“编写合适的HTML内容”是个非常“正统”的做法,在我有想法写这篇文章之前不久,我还认为这个问题并不难以解决。但是当我仔细想了UpdateProgress里填充的内容,发现它并不那么简单。而面临的主要难点,更确切地说应该是“麻烦点”,有如下两个:

  • 如何在跨浏览器的情况下得到Modal背景的尺寸?
  • 如何在滚动条移动时保持PopupDialog在浏览器中的位置?

这两个问题都不难,而且事实上在ModalPopupBehavior中都可以找到解决方案,但是我还是想自己写一些代码。不过写着写着,调试来调试去总是不那么理想,其实主要还是第一个跨浏览器的问题。最后还是翻了翻ModalPopupBehavior的代码,找到了它的相关实现,剥离出来由我们来使用。决定这么做之后,没花多少时间就解决问题了。

哎,作为一个开发人员,做事还是要谦虚谨慎啊,一定要多多吸取前人的经验来提高自己。

最后得到的结果,是一个轻量级的UpdateProgress实现。为什么说是“轻量级”的呢?因为编写的代码少,但是代码本身不具有很高的通用性,在使用时还需要根据具体的情况来作一些修改。

首先,我们先在页面上随意放一个UpdatePanel和UpdateProgress,里面的内容都非常简单,如下:

<div style="height: 2000px;">
    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
            <%= DateTime.Now %>
            <asp:Button ID="Button1" runat="server" Text="Button"
	        OnClick="Button1_Click" />
        </ContentTemplate>
    </asp:UpdatePanel>
</div>

<asp:UpdateProgress ID="UpdateProgress1" runat="server">
    <ProgressTemplate>
        <div id="modalBackground"></div>
        <div id="animationDialog">
            <img src="animated_loading.gif" alt="Loading" />
            Working on your request...
        </div>
    </ProgressTemplate>
</asp:UpdateProgress>

 

在UpdateProgres中,我们放置一个id为modalBackground的div作为Modal背景,还有一个id为animationDialog的div,这才是真正用作UpdateProgress提示的内容。

然后,我们在页面上先准备一些稳定的CSS Style,如下:

html
{
    font-zize : 10pt;
    font-family : Verdana;
}
#modalBackground
{
    background-color : gray;
    filter : alpha(opacity=70);
    opacity : 0.7;
    position : absolute;
    top : 0px;
    left : 0px;
}
#animationDialog
{
    position : absolute;
    border : solid 1px black;
    color : Black;
    background-color : #ffffae;
    font-family : Arial;
    font-size : 8pt;
    font-weight : bold;
    line-height : 30px;
    height : 30px;
    padding-left : 5px;
    padding-right : 5px;
}

 

接着就是最为关键的JavaScript代码了,它有两个作用,一是用于调节Modal背景的尺寸,二是调整animationDialog的位置(在这里我就将其固定在左上角),如下:

function getClientBounds()
{
    var clientWidth;
    var clientHeight;
    switch(Sys.Browser.agent) {
        case Sys.Browser.InternetExplorer:
            clientWidth = document.documentElement.clientWidth;
            clientHeight = document.documentElement.clientHeight;
            break;
        case Sys.Browser.Safari:
            clientWidth = window.innerWidth;
            clientHeight = window.innerHeight;
            break;
        case Sys.Browser.Opera:
            clientWidth = Math.min(window.innerWidth, 
                document.body.clientWidth);
            clientHeight = Math.min(window.innerHeight,
                document.body.clientHeight);
            break;
        default:  // Sys.Browser.Firefox, etc.
            clientWidth = Math.min(window.innerWidth,
                document.documentElement.clientWidth);
            clientHeight = Math.min(window.innerHeight,
                document.documentElement.clientHeight);
            break;
    }

    return new Sys.UI.Bounds(0, 0, clientWidth, clientHeight);
}

function resizeElements()
{
    var clientBounds = getClientBounds();
    var clientWidth = clientBounds.width;
    var clientHeight = clientBounds.height;

    var bg = $get("modalBackground");    
    bg.style.width = Math.max(
            Math.max(document.documentElement.scrollWidth, document.body.scrollWidth),
	    clientWidth) + 'px';
    bg.style.height = Math.max(
            Math.max(document.documentElement.scrollHeight, document.body.scrollHeight),
	    clientHeight) + 'px';

    var scrollLeft = (document.documentElement.scrollLeft ?
            document.documentElement.scrollLeft : document.body.scrollLeft);
    var scrollTop = (document.documentElement.scrollTop ?
            document.documentElement.scrollTop : document.body.scrollTop);    
    var dialog = $get("animationDialog");
    dialog.style.left = scrollLeft + "px";
    dialog.style.top = scrollTop + "px";
}

$addHandler(window, "scroll", resizeElements);
$addHandler(window, "resize", resizeElements);
resizeElements();

 

resizeElements方法的作用就是调节元素尺寸和位置。但是从获得Modal背景尺寸的工作中就可以发现,世界上存在那么多不同的浏览器实现有时真的是一件让人痛苦的事情。getClientBounds方法的作用是获得浏览器可视区域的大小,这段实现是从AjaxControlTookit中的Common.js中提取出来的。然后对元素的位置和大小进行设置的方式相信大家能够轻松地看明白,仔细想想也就可以理解DOM元素各个属性的具体含义了。最后,我们会在window的resize和scroll事件中调整DOM元素的属性——这是显而易见的。

这个示例的效果如下:

sample

 

以上就是Modal UpdateProgress实现方式了,朋友们可以尝试着移动滚动条,此时UpdateProgress会停留在左上角——可惜延迟是不可避免的。

嘿,既然这个是“轻量级”的实现,那么“重量级”的做法是什么呢?其实我正在写一个ModalUpdateProgress控件,算是UpdateProgress的扩展吧。这次可真要用到ModalPoupExtender了,其后果就是可能一个小小的功能就需要引入较多脚本代码。这其实是一个AjaxControlToolkit长久以来的一个问题。大家要不和我一起想想,该如何解决或者缓解这个问题呢?当然,不限于所谓的ModalUpdateProgress或者ModalPopupBehavior,这是为整个AjaxControlTookit要求的。

 

代码下载

点击这里浏览使用效果。

Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

34 条回复

  1. dansinge[未注册用户]
    *.*.*.*
    链接

    dansinge[未注册用户] 2007-03-22 09:09:00

    up

  2. 喜欢吹风的感觉
    *.*.*.*
    链接

    喜欢吹风的感觉 2007-03-22 09:29:00

    今天才识老赵的庐山真面目,呵呵,有股强大的书呆子气.

  3. 老赵
    admin
    链接

    老赵 2007-03-22 10:34:00

    @喜欢吹风的感觉
    啥啥?

  4. Aaron[未注册用户]
    *.*.*.*
    链接

    Aaron[未注册用户] 2007-03-22 11:27:00

  5. Maverick[未注册用户]
    *.*.*.*
    链接

    Maverick[未注册用户] 2007-03-22 11:35:00

    昨天才因为同样的问题查看过ajax docs, 其中有这么一段关于UpdateProgress的

    var prm = Sys.WebForms.PageRequestManager.getInstance();
    prm.add_initializeRequest(InitializeRequest);
    prm.add_endRequest(EndRequest);

    function InitializeRequest(sender, args) {}
    function EndRequest (sender, args) {}

    在InitializeRequest其中调用Behvaior的hide和show方法来控制ModalDialog呢?

  6. 老赵
    admin
    链接

    老赵 2007-03-22 11:40:00

    @Aaron
    谢谢,不过他的功能和我的不同。:)

  7. 老赵
    admin
    链接

    老赵 2007-03-22 11:41:00

    @Maverick
    这就是UpdateProgress的实现方式。
    不过如果我要操作UpdateProgress就不是那么简单的了,例如如果有多个UpdateProgress呢?如果UpdateProgress是和一个UpdatePanel相关联的呢?其实UpdatePanel本身内部也有些逻辑,要用一个“正统”的解决方案并不那么简单。:)

  8. Leem
    *.*.*.*
    链接

    Leem 2007-03-22 14:31:00

    有没有办法让UpdateProgress去执行一些脚本呢?

  9. liuyuer
    *.*.*.*
    链接

    liuyuer 2007-03-22 16:11:00

    请问在ModalPopupExtender中的Control如何来触发一个server side 的方法呢?

  10. 老赵
    admin
    链接

    老赵 2007-03-22 17:46:00

    @Leem
    目前吗?我认为没有办法。您需要什么效果呢?

  11. 老赵
    admin
    链接

    老赵 2007-03-22 17:47:00

    @liuyuer
    ModalPopupExtender,顾名思义是一个Extender,您说的ModalPopupExtender 的Control是什么意思呢?

  12. lovelyguy[未注册用户]
    *.*.*.*
    链接

    lovelyguy[未注册用户] 2007-03-23 09:15:00

    哈哈

  13. 魏晋遗疯
    *.*.*.*
    链接

    魏晋遗疯 2007-03-23 16:39:00

    楼上的duhaha死去吧

    老赵,怎么浏览这篇文章需要拖动水平滚动条啊?好像以前的文章不用的,我的分辨率可是1280X1024的,不太方便啊,能调调么?

  14. deerchao
    *.*.*.*
    链接

    deerchao 2007-03-23 16:45:00

    删了duhaha的留言就不用滚动条了。

  15. 老赵
    admin
    链接

    老赵 2007-03-23 16:57:00

    @魏晋遗疯
    已删除,duhaha的广告撑开了。我的文章都调整成1024宽度能全屏正常访问。

  16. 马哥
    *.*.*.*
    链接

    马哥 2007-03-23 17:51:00

    我的座右铭还是“自己动手远好过别人的施舍”呢

    今天看了老赵的“作为一个开发人员,做事还是要谦虚谨慎,一定要多多吸取前人的经验来提高自己”这番话,才发觉自己有很多地方要多谦虚学习别人才是。

  17. 老赵
    admin
    链接

    老赵 2007-03-23 18:11:00

    @马哥
    独立、并不表示拒绝别人帮助。吸取前人经验,基于别人的成果做事,是为了让自己看的更远。:)

  18. JesseZhao
    *.*.*.*
    链接

    JesseZhao 2007-03-26 08:15:00

    呵呵,文章写的不错,很喜欢

  19. 许浩[未注册用户]
    *.*.*.*
    链接

    许浩[未注册用户] 2007-07-02 11:07:00

    偶看不太懂你写的
    后来把你的修改了一下 也实现了
    原理是不是在UpdateProgress 里放了一个 灰色背景的层
    提交的时候 层显示 所以层下面的控件就不能点啦
    谢谢 赵老师

  20. 老赵
    admin
    链接

    老赵 2007-07-02 11:38:00

    @许浩
    原理就是这样的,其实就是封装成了控件,并且处理了一些细节。:)

  21. 叶子绿了
    *.*.*.*
    链接

    叶子绿了 2007-08-08 14:44:00

    赵老师:
    你在Button1_Click事件里面是 Thread.Sleep(5000);
    如果想根据系统响应时间,这要怎么实现.
    假如往数据库里面添加数据,执行过程会提示用户:程序正在进行,请稍候...
    添加完成之后重新显示.这个要怎么做?
    谢谢!

  22. 叶子绿了
    *.*.*.*
    链接

    叶子绿了 2007-08-08 14:58:00

    我知道怎么做了,在Button1_click里面执行添加数据的程序
    再在updatepanel里面显示出来就可以了.

  23. song0320[未注册用户]
    *.*.*.*
    链接

    song0320[未注册用户] 2007-08-31 13:24:00

    其实我感觉是不是可以用onpropertychange来激发UpdateProgress的显示事件这样在事件里写遮照层的扩展

  24. 老赵
    admin
    链接

    老赵 2007-08-31 14:46:00

    @song0320
    应该也是可以的。:)

  25. Leisang[未注册用户]
    *.*.*.*
    链接

    Leisang[未注册用户] 2007-12-09 14:48:00

    太好了,正是我要的内容。另外问下
    function resizeElements()函数是ajax自动执行的吗?

  26. 老赵
    admin
    链接

    老赵 2007-12-09 16:49:00

    @Leisang
    并非AJAX,代码中其实可以看到它被执行的。

  27. 何杰
    *.*.*.*
    链接

    何杰 2008-02-01 11:18:00

    老赵你好,遇到了一个非常头疼的问题:
    在框架页面中使用ModalPopupExtender,弹出后,页面的其他部分没有被全部覆盖(不包括框架中其他页面,本页面都没有被覆盖完),但以下正常:
    1、在页面没有异步回送时,弹出后是覆盖正常,
    2、页面不是框架页面时,弹出后是覆盖正常

  28. 老赵
    admin
    链接

    老赵 2008-02-01 12:06:00

    @何杰
    框架页面的确会有问题,这个很难解决,建议了解ModalPopupExtender的实现方法,然后自己做。

  29. 一生何求[未注册用户]
    *.*.*.*
    链接

    一生何求[未注册用户] 2008-02-17 11:11:00

    感谢!正要用到这个!
    但是有一个缺点:在ie中div不能屏蔽掉dropdownlist等控件,建议再写一个在div下加一个iframe的版本!

  30. lzhshen01[未注册用户]
    *.*.*.*
    链接

    lzhshen01[未注册用户] 2008-02-18 09:38:00

    把图片的位置设置为如下,就可以居中了,并且不受滚动条的影响

    background-position:center;
    height:20px;
    left:50%;
    margin-left:-10px;
    margin-top:-10px;
    position:fixed;
    top:50%;
    width:20px;

  31. FEIM Studios
    *.*.*.*
    链接

    FEIM Studios 2008-07-23 00:10:00

    路过。

  32. wwyjx
    *.*.*.*
    链接

    wwyjx 2008-08-29 12:29:00

    如果page上有个Dropdown List的话,显示就很奇怪。

  33. 刘先生阿斯顿发[未注册用户]
    *.*.*.*
    链接

    刘先生阿斯顿发[未注册用户] 2008-11-03 15:27:00

    看了贵先生MSDN的Ajax深入浅出系列讲座来下代码的,顶一下了。。。。

  34. 轨迹路上[未注册用户]
    *.*.*.*
    链接

    轨迹路上[未注册用户] 2008-12-17 00:21:00

    这样也可以了~~
    <asp:UpdateProgress ID="UpdateProgress1" runat="server" DisplayAfter="0">
    <ProgressTemplate>
    <ajaxToolkit:ModalPopupExtender ID="ModalPopupExtender1" runat="server" TargetControlID="UpdatePanel1" PopupControlID="PNL1" />
    <asp:Panel ID="PNL1" runat="server" style="display:none; width:200px; background-color:White; border-width:1px; border-color:Black; border-style:solid; padding:20px;">
    <img alt="" src="images/loading.gif" /> 请稍后!</asp:Panel>
    </ProgressTemplate>
    </asp:UpdateProgress>

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我