老赵点滴


  先做人,再做技术人员,最后做程序员。
  我的理想:“让外国人看中国人写的技术书籍和文章”。Try as I might
posts - 290, comments - 10769, trackbacks - 147, articles - 6
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

  又被问了这样一个问题: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,里面的内容都非常简单,如下:

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,如下:

CSS
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的位置(在这里我就将其固定在左上角),如下:

JavaScript代码
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要求的。

 

  代码下载

点击这里浏览使用效果。

Feedback

#1楼    回复  引用    

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

#2楼    回复  引用  查看    

2007-03-22 09:29 by 喜欢吹风的感觉      
今天才识老赵的庐山真面目,呵呵,有股强大的书呆子气.

#3楼 [楼主]   回复  引用  查看    

2007-03-22 10:34 by Jeffrey Zhao      
@喜欢吹风的感觉
啥啥?

#4楼    回复  引用    

2007-03-22 11:27 by Aaron [未注册用户]
提供一個參考範例 http://flansamples.googlepages.com/FlanControls.html

#5楼    回复  引用    

2007-03-22 11:35 by Maverick [未注册用户]
昨天才因为同样的问题查看过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楼 [楼主]   回复  引用  查看    

2007-03-22 11:40 by Jeffrey Zhao      
@Aaron
谢谢,不过他的功能和我的不同。:)

#7楼 [楼主]   回复  引用  查看    

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

#8楼    回复  引用  查看    

2007-03-22 14:31 by Leem      
有没有办法让UpdateProgress去执行一些脚本呢?

#9楼    回复  引用  查看    

2007-03-22 16:11 by liuyuer      
请问在ModalPopupExtender中的Control如何来触发一个server side 的方法呢?

#10楼 [楼主]   回复  引用  查看    

2007-03-22 17:46 by Jeffrey Zhao      
@Leem
目前吗?我认为没有办法。您需要什么效果呢?

#11楼 [楼主]   回复  引用  查看    

2007-03-22 17:47 by Jeffrey Zhao      
@liuyuer
ModalPopupExtender,顾名思义是一个Extender,您说的ModalPopupExtender 的Control是什么意思呢?

#12楼    回复  引用    

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

#13楼    回复  引用  查看    

2007-03-23 16:39 by 魏晋遗疯      
楼上的duhaha死去吧

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

#14楼    回复  引用  查看    

2007-03-23 16:45 by deerchao      
删了duhaha的留言就不用滚动条了。

#15楼 [楼主]   回复  引用  查看    

2007-03-23 16:57 by Jeffrey Zhao      
@魏晋遗疯
已删除,duhaha的广告撑开了。我的文章都调整成1024宽度能全屏正常访问。

#16楼    回复  引用  查看    

2007-03-23 17:51 by 马哥      
我的座右铭还是“自己动手远好过别人的施舍”呢

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

#17楼 [楼主]   回复  引用  查看    

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

#18楼    回复  引用  查看    

2007-03-26 08:15 by JesseZhao      
呵呵,文章写的不错,很喜欢

#19楼    回复  引用    

2007-07-02 11:07 by 许浩 [未注册用户]
偶看不太懂你写的
后来把你的修改了一下 也实现了
原理是不是在UpdateProgress 里放了一个 灰色背景的层
提交的时候 层显示 所以层下面的控件就不能点啦
谢谢 赵老师

#20楼 [楼主]   回复  引用  查看    

2007-07-02 11:38 by Jeffrey Zhao      
@许浩
原理就是这样的,其实就是封装成了控件,并且处理了一些细节。:)

#21楼    回复  引用  查看    

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

#22楼    回复  引用  查看    

2007-08-08 14:58 by 叶子绿了      
我知道怎么做了,在Button1_click里面执行添加数据的程序
再在updatepanel里面显示出来就可以了.

#23楼    回复  引用    

2007-08-31 13:24 by song0320 [未注册用户]
其实我感觉是不是可以用onpropertychange来激发UpdateProgress的显示事件这样在事件里写遮照层的扩展

#24楼 [楼主]   回复  引用  查看    

2007-08-31 14:46 by Jeffrey Zhao      
@song0320
应该也是可以的。:)

#25楼    回复  引用    

2007-12-09 14:48 by Leisang [未注册用户]
太好了,正是我要的内容。另外问下
function resizeElements()函数是ajax自动执行的吗?

#26楼 [楼主]   回复  引用  查看    

2007-12-09 16:49 by Jeffrey Zhao      
@Leisang
并非AJAX,代码中其实可以看到它被执行的。

#27楼    回复  引用  查看    

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

#28楼 [楼主]   回复  引用  查看    

2008-02-01 12:06 by Jeffrey Zhao      
@何杰
框架页面的确会有问题,这个很难解决,建议了解ModalPopupExtender的实现方法,然后自己做。

#29楼    回复  引用    

2008-02-17 11:11 by 一生何求 [未注册用户]
感谢!正要用到这个!
但是有一个缺点:在ie中div不能屏蔽掉dropdownlist等控件,建议再写一个在div下加一个iframe的版本!

#30楼    回复  引用    

2008-02-18 09:38 by lzhshen01 [未注册用户]
把图片的位置设置为如下,就可以居中了,并且不受滚动条的影响

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

#31楼    回复  引用  查看    

2008-07-23 00:10 by FEIM Studios      
路过。

#32楼    回复  引用  查看    

2008-08-29 12:29 by wwyjx      
如果page上有个Dropdown List的话,显示就很奇怪。

标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2007-03-28 05:39 编辑过


相关链接: