在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
今天也不知道写不写的完了,最近闲下来了,却感冒了,早上起来都不会说话了,不过幸亏咱不是靠嘴皮子过活了,哎~~~~窃喜吧 上一篇简单写到UpdatePanel的一些好处和坏处,这一篇呢,就细致的认识一下UpdatePanel这个控件,并合理的使用它
UpdatePanel的一些属性:
看一个UpdatePanel的示例
相关的API
写一个实例 <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> <asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager> <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional"> <ContentTemplate> <%= DateTime.Now %> </ContentTemplate> </asp:UpdatePanel> <asp:Button ID="Button1" runat="server" Text="Button" /> </form> </body> </html>
这时点击Button,UpdatePanel是不更新的,如果想让时间异步更新,我们可以在页面的Page_Load事件处理程序中加入 ScriptManager.GetCurrent(this.Page).RegisterAsyncPostBackControl(this.Button1);
这样点击Button,页面已经不是传统的回送了,这就是RegisterAsyncPostBackControl起的作用,但是时间还是没有变化,说明UpdatePanel没有更新,我们再在Button的Click事件处理程序中,加入 this.UpdatePanel1.Update();
这时再点击按钮,时间更新,因为我们强制了UpdatePanel1的更新 其实呢,这里更直观的一种做法是把Button1设置到UpdatePanel1的AsyncPostBackTriggers中
然后,我们再在UpdatePanel中加入一个按钮,点击这个按钮,会产生一个异步的回送,引起UpdatePanel1的更新,如果我们想让这个按钮引发一个传统的回送,就可以在Page_Load事件处理程序中加入一下代码 ScriptManager.GetCurrent(this.Page).RegisterPostBackControl(this.Button2); 这时,我们再点击Button2时候,引发的就是一个传统的回送,这个我们可以通过滚动条或者前进后退按钮,证明它是一个传统的回送 这时,如果我们再在UpdatePanel1里注册一个AsyncPostBackTrigger为Button2,就会出现一个应用程序错误,原因显而易见
相关控件UpdateProgress 当网页包含一个或多个用于部分页呈现的 UpdatePanel 控件时,UpdateProgress 控件可帮助您设计更为直观的 UI。如果部分页更新速度较慢,则可以使用 UpdateProgress 控件来提供有关更新状态的可视反馈。可以在页上放置多个 UpdateProgress 控件,其中每个控件都与不同的 UpdatePanel 控件相关联。也可以使用一个 UpdateProgress 控件,并将其与页上的所有 UpdatePanel 控件关联,常用的情况呢,就是在类似网速比较慢,或者请求数据量大或者会拖延较长时间的时候,使用UpdateProgress和用户进行交互,让用户知道页面在更新,而不是一种假死或者其他的状态 UpdateProgress的几个属性
Timer Timer 控件是一个服务器控件,它会将一个 JavaScript 组件嵌入到网页中。当经过 Interval 属性中定义的时间间隔时,该 JavaScript 组件将从浏览器启动回发。您可以在运行于服务器上的代码中设置 Timer 控件的属性,这些属性将传递到该 JavaScript 组件。 若回发是由 Timer 控件启动的,则 Timer 控件将在服务器上引发 Tick 事件。当页发送到服务器时,可以创建 Tick 事件的事件处理程序来执行一些操作。 设置 Interval 属性可指定回发发生的频率,而设置 Enabled 属性可打开或关闭 Timer。Interval 属性是以毫秒为单位定义的,其默认值为 60,000 毫秒(即 60 秒)。 这里需要注意一点: 将 Timer 控件的 Interval 属性设置为一个较小值会产生发送到 Web 服务器的大量通信,对服务器的压力会明显提升。使用 Timer 控件可以仅按所需的频率刷新内容
一个UpdateProgress示例 在页面中添加如下代码: <form id="form1" runat="server"> <asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager> <asp:UpdatePanel ID="UpdatePanel1" runat="server"> <ContentTemplate> <%= DateTime.Now %><br /> <asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" /> </ContentTemplate> </asp:UpdatePanel> </form>
然后在Button1的Click事件处理程序中,写入 System.Threading.Thread.Sleep(3000);
这样就可以让服务器端在按钮点击后等待三秒后再发回数据,这样,我们在点击按钮3秒之内,页面就会假死在那里,所以我们需要在这三秒内给用户一个提示 所以,我们在UpdatePanel上方添加如下代码 <asp:UpdateProgress ID="UpdateProgress1" runat="server" DynamicLayout="false" DisplayAfter="500"> <ProgressTemplate> 加载中... </ProgressTemplate> </asp:UpdateProgress>
这时,在页面中UpdatePanel上方的位置就出现了一块空白,这就是DynamicLayout="false"的效果,如果设置为True,则不会出现这块空白 当我们点击Button1后半秒(DisplayAfter="500")后,UpdatePanel上方出现“加载中…”字样,UpdatePanel更新完毕后,字样消失,这就是UpdateProgress给出的提示
注意:如果这里我们在UpdatePanel中加入AsyncPostBackTrigger指定一个UpdatePanel外部的控件作为UpdatePanel更新的触发器,并且在UpdateProgress中设置了AssociatedUpdatePanelID="UpdatePanel1",则外部设置的控件的相应事件的触发,UpdateProgress不会起作用‘
ASP.NET 2.0脚本注册比如我们需要在用户点击一个按钮时候,弹出一个提示框之类的东西,我们往往会通过Response.Writer然后输出一段javascript,这在通常情况下是可行的,但是我们看接下来的一个示例 页面代码: <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> <asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager> <asp:UpdatePanel ID="UpdatePanel1" runat="server"> <ContentTemplate> <asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" /> </ContentTemplate> </asp:UpdatePanel> <asp:Button ID="Button2" runat="server" Text="Button" onclick="Button2_Click" /> </form> </body> </html> 在两个按钮的单击事件处理程序中,加入如下代码: Response.Write("<script>alert('Xiaoyaojian');</script>");
这样,我们可以发现,在单击UpdatePanel外的一个按钮时,程序正常弹出一个提示框,但是当我们点击UpdatePanel内的一个按钮的时候,页面不能弹出提示框,并且会出现一个错误,这是一个典型的问题,其实使用这种方式给客户端写入脚本代码是一个非常拙劣的做法,接下来我们看一些ASP.NET 2.0提供的一些标准的操作脚本的方法
一个示例 创建一个页面,在页面中添加一个服务端按钮,在按钮的单击事件处理程序中,加入一下代码: ClientScriptManager csm = this.ClientScript; csm.RegisterArrayDeclaration("hello", "1,2,3");//常见一个名为hello的数组,内容为1,2,3 csm.RegisterClientScriptBlock(this.GetType(), "afunction", "function alertMessage(){alert('xiaoyaojian');}", true);//注册一个代码段 csm.RegisterClientScriptInclude("jsDocScript", "jsDoc.js");//引入一个名为jsDoc.js的文件,jsDocScript作为它的key,防止重复载入 csm.RegisterExpandoAttribute(this.Button1.ClientID, "xiaobai", "xiaoyaojian");//为Button1添加一个名为xiaobai的属性,值为xiaoyaojian 注意一定要是控件的ClientID,因为服务器端控件发送到客户端后,它的ID是经过一定的规则转变过的 csm.RegisterHiddenField("xiaobai", "xiaoyaojian");//在页面中添加一个隐藏域 csm.RegisterOnSubmitStatement(this.GetType(), "xiaoyaojian", "return window.confirm('Are you sure to delete?')");//可以添加一段语句,如果返回true,则此次提交可以成功,如果返回false,则提交不会成功 csm.RegisterStartupScript(this.GetType(), "xiaoyaojian", "<script>alert('xiaoyaojian');</script>"); 打开网页,我们可以在页面源代码中找下如下内容(与上面的语句一一对应): 1. <script type="text/javascript"> //<![CDATA[ var hello = new Array(1,2,3); //]]> </script> 2. <script type="text/javascript"> //<![CDATA[ function alertMessage(){alert('xiaoyaojian');}//]]> </script> 3. <script src="jsDoc.js" type="text/javascript"></script> 4. <input type="hidden" name="xiaobai" id="xiaobai" value="xiaoyaojian" /> 5. <script type="text/javascript"> //<![CDATA[ function WebForm_OnSubmit() { return window.confirm('Are you sure to delete?'); return true; } //]]> </script> 6. <script>alert('xiaoyaojian');</script></form> 这里需要讲一下第五句和第六句的区别,他们两个方法注册脚本的区别就在,RegisterOnSubmitStatement将脚本注册在了显示内容的最上边,而RegisterStartupScript则刚好相反
那么,在异步更新状态中注册脚本,则是使用ScriptManager对应的那几个静态方法
一个异步更新状态下注册脚本的示例 常见一个页面 <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> <asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager> <asp:UpdatePanel ID="UpdatePanel1" runat="server"> <ContentTemplate> <%= DateTime.Now %><br /> <asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" /> </ContentTemplate> </asp:UpdatePanel> </form> </body> </html> 在按钮的单击事件处理程序中加入如下代码: ScriptManager.RegisterStartupScript(this.UpdatePanel1, this.GetType(), "key_1", "alert('xiaoyaojian');", true);
第一个参数,是一个Control类型的参数(重载为Page类型),表示为哪个控件注册脚本,这就是多出来的那个参数,最后一个参数,表示是不是为注册的脚本加入一个<script>标记 这时我们在点击按钮,就可以正常弹出提示框了,这就解决了我们一开始遗留的那个问题
错误处理服务器ScriptManager相应设置 ___AllowCustomErrorsRedirect属性:遇到错误时,是否根据web.config中的设置进行跳转,默认设置为True ___AsyncPostBackError事件:异步刷新中遇到错误时,此事件被触发 ___AsyncPostBackErrorMessage属性:客户端接受到的错误信息 在我们自行处理错误的时候,就需要在客户端响应PageRequestManager中的endRequest事件,并将errorHandled属性设置为True
一个关于错误处理的示例 现在如果使用Visual Studio 2008中创建网站,默认的customErrors结点是被注释掉的,我们对这个节点做如下操作 1.首先将注释取消,然后设置mode="On",defaultRedirect设置为我们要跳转到的错误页面,这里我们让他跳转到我们将要创建的Error.aspx, 2,创建这个Error.aspx,里面添加一些自定义的错误提示 3.创建一个要发生错误的页面 <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> <asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager> <asp:UpdatePanel ID="UpdatePanel1" runat="server"> <ContentTemplate> <asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" /> </ContentTemplate> </asp:UpdatePanel> </form> </body> </html> 在按钮点击事件中抛出一个异常,然后浏览页面,点击按钮,就会自动跳转到我们设定的默认错误页面
那么,如果想在当前出现错误的页面中处理错误,就要这样做
首先把AllowCustomErrorsRedirect="false" 然后在页面中添加如下代码 <div id="error"></div> <script type="text/javascript" language="javascript"> Sys.WebForms.PageRequestManager.getInstance().add_endRequest(function(sender, e) { e.set_errorHandled(true);//表示我们已经处理了这个错误 $get("error").innerHTML = "出现一个错误"; }); </script> 一个动态创建UpdatePanel的示例:
UpdatePanel updatePanel = new UpdatePanel(); updatePanel.ID = "up1"; this.Form.Controls.Add(updatePanel);//这是服务端控件的要求,必须添加到Form中 LiteralControl literalControl = new LiteralControl(DateTime.Now.ToString()); updatePanel.ContentTemplateContainer.Controls.Add(literalControl);//这里是添加到ContentTemplateContainer,而不是ContentTemplate Button button = new Button(); button.Text = "按钮"; updatePanel.ContentTemplateContainer.Controls.Add(button); PageRequestManager类
PageRequestManager在客户端形成的声明周期(异步刷新时触发)
PageRequestManager__initializeRequest事件
常用的操作
一个示例 如果我们要在一个优先级高的异步回送发起时,取消已经发起的优先级较低的操作,而在一个优先级较低的异步回送发起时,如果一优先级高的异步回送还没有完成时,而阻止此次异步回送时,我们就可以在PageRequestManager的initializeRequest中做如下操作
<script language="javascript" type="text/javascript"> var lastPostBackButtonId = null; var btnPrecedenceId = "<%= this.btnPrecedence.ClientID %>";//优先级高的按钮的客户端ID Sys.WebForms.PageRequestManager.getInstance().add_initializeRequest( function(sender, e) { var prm = Sys.WebForms.PageRequestManager.getInstance(); if (prm.get_isInAsyncPostBack()) {//判断是否在异步会动过程中 if (lastPostBackButtonId == btnPrecedenceId) { e.set_cancel(true); //取消操作 //e.get_postBackElement().id 得到发起回送的元素ID if (e.get_postBackElement().id == btnPrecedenceId) { showMessage("不可重复发起优先的刷新。"); } else { showMessage("请等待优先的刷新结束。"); } } else { if (e.get_postBackElement().id == btnPrecedenceId) { showMessage("发起优先的刷新,普通的刷新讲被取消"); } else { showMessage("重新发起普通的刷新,前一次提交将要被取消"); } } lastPostBackButtonId = e.get_postBackElement().id; } } ); </script> PageRequestManager__begingRequest事件
常用的操作:
一个强制显示UpdateProgress的示例 创建一个页面,添加ScriptManager并添加如下代码 <asp:UpdatePanel ID="UpdatePanel1" runat="server"> <ContentTemplate> <%= DateTime.Now %> <br /> <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button_Click" /> </ContentTemplate> <Triggers> <asp:AsyncPostBackTrigger ControlID="Button2" /> </Triggers> </asp:UpdatePanel> <asp:UpdateProgress ID="UpdateProgress1" runat="server" DisplayAfter="1000" AssociatedUpdatePanelID="UpdatePanel1"> <ProgressTemplate> <span style="color:Red">Loading...</span> </ProgressTemplate> </asp:UpdateProgress> <hr /> <asp:Button ID="Button2" runat="server" Text="Button" OnClick="Button_Click"/>
并在按钮的点击事件中,让他线程停止两秒种,这样我们会发现,在点击UpdatePanel外的一个按钮的时候,UpdateProgress并没有显示Loading字样,其实这就是在UpdateProgress绑定一个UpdatePanel后产生的一个问题,只有UpdatePanel内的控件触发的异步回送,UpdateProgress才会做出反映
我们要让这个UpdateProgress对外部控件引发的异步回送产生反映,就可以模仿UpdateProgress内的一个startRequest方法 在页面上我们嵌入如下代码
<script language="javascript" type="text/javascript"> Sys.WebForms.PageRequestManager.getInstance().add_beginRequest( function(sender, e) { if (e.get_postBackElement().id != "<%=this.Button2.ClientID %>") { return; } var updateProgress = $get("<%= this.UpdateProgress1.ClientID %>"); var dynamicLayout =<%=this.UpdateProgress1.DynamicLayout.ToString().ToLower() %>; if(dynamicLayout) { updateProgress.style.display="block"; } else { updateProgress.style.visibility="visible"; } }); </script>
这样,我们就实现了强制UpdateProgress的显示
PageRequestManager__pageLoading事件
常用操作
一个提示更新的UpdatePanel的示例 首先,我们创建一个用户控件,里面仅仅包含一个UpdatePanel用来显示当前事件,它的UpdateMode="Conditional",然后在它codefile中,加入如下代码 private static Random random = new Random(DateTime.Now.Millisecond); protected void Page_Load(object sender, EventArgs e) { if (random.NextDouble() > 0.5) { this.UpdatePanel1.Update(); } } 这样,他每次只有一般的几率会更新 创建一个页面,添加若干个上面的用户控件,然后在页面Loadin事件里,注册一个异步更新的按钮 如果我们要高亮显示更新的UpdatePanel,就可以利用pageLoading这个事件,在页面中加入如下代码:
<script language="javascript" type="text/javascript"> function highlightPanels(panels, clear) { for (var i = 0; i < panels.length; i++) { var panel = panels[i]; panel.style.border = clear ? "solid 0px white" : "solid 2px red"; } } Sys.WebForms.PageRequestManager.getInstance().add_pageLoading( function(sender, e) { var panelUpdating = Array.clone(e.get_panelsUpdating());//得到要更新的UpdatePanel highlightPanels(panelUpdating,false); window.setTimeout(function() { highlightPanels(panelUpdating,true)},2000); } ); </script> 这样,就可以提示用户哪个UpdatePanel将会被更新了,这就是一个典型利用pageLoading事件的例子
PageRequestManager___pageLoaded事件
常用操作
一个局部内容添加的示例 新建一个页面,添加ScriptManager,然后添加如下代码 <strong>Comment</strong><hr /><hr /> <div id="commentContainer"> <asp:UpdatePanel ID="UpdatePanel1" runat="server"> <ContentTemplate> <asp:Repeater ID="Repeater1" runat="server"> <ItemTemplate> <%# (Container.DataItem as Comment).Content %><br /> <i><%#(Container.DataItem as Comment).Time %></i> <hr /> </ItemTemplate> </asp:Repeater> </ContentTemplate> <Triggers> <asp:AsyncPostBackTrigger ControlID="Button1" /> </Triggers> </asp:UpdatePanel> </div> <br /> <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox><hr /> <asp:Button ID="Button1" runat="server" Text="Add Comment" onclick="Button1_Click" /> 然后,在页面的codefile里添加 private static List<Comment> Comments; protected void Page_Load(object sender, EventArgs e) { if (!this.IsPostBack) { Comments = new List<Comment>(); this.BindComments(); } } private void BindComments() { this.Repeater1.DataSource = Comments; this.Repeater1.DataBind(); } protected void Button1_Click(object sender, EventArgs e) { Comment comment = new Comment(); comment.Content = this.TextBox1.Text; comment.Time = DateTime.Now; Comments.Add(comment); //this.Repeater1.DataSource = new Comment[] { comment }; this.BindComments(); //this.Repeater1.DataBind(); }
Comment类就是简单的两个公有字段Content和Time,这样我们就完成了一个类似论坛回帖的这么一个效果,但是,我们现在每次更新都是更新的整个UpdatePanel,随着这个回复的增加,服务器端需要处理并发回的数据量就会一点一点增加,所以我们要做一下的操作来减少这样的没有必要的数据量的传输
首先我们要知道,服务器端是怎么知道要更新的是哪个UpdatePanel的,它是通过UpdatePanel的ID来找到的,我们要做的就是让要寻找的不是当前要更新的ID 首先修改按钮点击事件的代码 protected void Button1_Click(object sender, EventArgs e) { Comment comment = new Comment(); comment.Content = this.TextBox1.Text; comment.Time = DateTime.Now; //Comments.Add(comment); this.Repeater1.DataSource = new Comment[] { comment }; //this.BindComments(); this.Repeater1.DataBind(); }
然后在页面中,锲入如下的javascript代码 <script language="javascript" type="text/javascript"> Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded( function(sender, e) { var upId = "<%=this.UpdatePanel1.ClientID %>";//得到UpdatePanel的客户端ID var refreshedPanels = e.get_panelsUpdated();//得到所有已经更新的UpdatePanel for (var i = 0; i < refreshedPanels.length; i++) {//遍历所有已经更新的UpdatePanel if (refreshedPanels[i].id == upId) {//如果发现我们需要的UpdatePanel已经更新 refreshedPanels[i].id = upId + Math.floor(9999 * Math.random());//首先改变原来的UpdatePanel的ID var div = document.createElement("div");//创建一个DIV div.id = upId;//把这个DIV的ID设置为要更新的UpdatePanel的ID $get("commentContainer").appendChild(div);//然后把它添加到大的DIV的末尾 return; } } } ); </script>
这样我们新建了一个DIV,让传过来的新的数据放到这个DIV里,我们就完成了和一开始一样的功能,而且,我们现在用一些工具的查看的时候,每回发回的 |
请发表评论