13.3 UpdatePanel控件
UpdatePanel控件是ASP.NET中Ajax功能的中心部分。它们与ScriptManager控件一起使用,以启用部分页呈现。本节介绍UpdatePanel控件的概念及其应用。
13.3.1 UpdatePanel简介
UpdatePanel在ScriptManager控件开启了Ajax功能之后,为页面中需要局部更新的地方设置一个区域。UpdatePanel控件相当于一个容器,在页面中占据一定的区域,该区域的内容可在页面整体没有更新的状态下进行更新,即局部更新。
UpdatePanel控件通过指定页中无须刷新整个页面即可更新的区域发挥作用。此过程由ScriptManager服务器控件和客户端PageRequestManager类来协调。当启用部分页更新时,控件可以通过异步方式发布到服务器。异步回发的行为与常规回发类似:生成的服务器页执行完整的页和控件生命周期。不过,通过使用异步回发,可将页更新限制为包含在UpdatePanel控件中并标记为要更新的页区域。服务器仅将受影响的元素的HTML标记发送到浏览器。在浏览器中,客户端PageRequestManager类执行文档对象模型(DOM)操作以将现有HTML替换为更新的标记。
使用异步回发或使用XMLHTTPRequest对象时,如果URL包含双字节字符,则可能发生回发错误。此问题可以通过下面的方法得到解决:在页面的head元素中加入<base href="url"/>元素,其中href属性设置为引用该页面的URL编码的字符串。可以动态添加到服务器代码中的此元素。
UpdatePanel控件的呈现在只需更新部分区域时减少了同步回发和更新整个页面的需要。由于部分区域更新减少了整页回发时的屏幕闪烁并提高了网页交互性,因而改善了用户体验。UpdatePanel控件的常用属性如表13-4所示。
表13-4 UpdatePanel控件的常用属性
13.3.2 UpdatePanel异步更新
启用UpdatePanel呈现后,控件可执行一个回发来更新整个页,也可执行异步回发来更新一个或多个UpdatePanel控件的内容。控件是否导致异步回发并更新UpdatePanel控件视以下情况而定,可根据UpdatePanel控件的UpdateMode属性来设置,如表13-5所示。
表13-5 UpdateMode属性与对应的页面更新情况
在UpdateMode设置为Always时不允许同时将ChildrenAsTriggers属性设置为false,这会引发异常。
当UpdatePanel控件执行异步发布时,会添加自定义HTTP头。一些代理会移除此自定义HTTP头。如果发生此情况,则服务器会将请求作为常规回发进行处理,这会引发客户端错误。若要解决此问题,需要在执行异步发布时插入自定义窗体字段。然后检查服务器代码中的头或自定义窗体字段。
可以使用多个UpdatePanel控件来单独更新不同的页区域。第一次呈现包含一个或多个UpdatePanel控件的页后,会呈现所有UpdatePanel控件的所有内容,并会将这些内容发送到浏览器。在随后执行异步回发时,根据面板设置以及各面板的客户端或服务器逻辑的不同,可能不会更新所有UpdatePanel控件的内容。
此外,还可以在以下情况下使用UpdatePanel控件。
(1)在用户控件中。
(2)在母版页和内容页上。
(3)嵌套在其他UpdatePanel控件中。
(4)在模板化控件(如GridView或Repeater控件)内部。
在使用UpdatePanel控件时,可使用表13-6中的方法来实现页面局部更新。
表13-6 实现页面局部更新的方法
如果在异步回发期间出现页面错误,则会引发AsyncPostBackError事件。以何种方式将服务器上的错误发送到客户端取决于AllowCustomErrorsRedirect属性、AsyncPostBackErrorMessage属性以及Web.config文件的自定义错误部分。
可以以编程方式添加UpdatePanel控件,但不能以编程方式添加触发器。若要创建类似触发器的行为,可以将页上的控件注册为异步回发控件。可以通过调用ScriptManager控件的RegisterAsyncPostBackControl()方法来执行此操作。然后,可以创建一个为响应异步回发而运行的事件处理程序,并在该处理程序中调用UpdatePanel控件的Update()方法。
可以通过声明方式向UpdatePanel控件添加内容,也可以在设计器中通过使用ContentTemplate属性来添加内容。在标记中,将此属性作为ContentTemplate元素公开。若要以编程方式添加内容,建议使用ContentTemplateContainer属性。
当首次呈现包含一个或多个UpdatePanel控件的页时,将呈现UpdatePanel控件的所有内容并将这些内容发送到浏览器。在后续异步回发中,可能会更新各个UpdatePanel控件的内容。更新将与面板设置、导致回发的元素以及特定于每个面板的代码有关。
默认情况下,UpdatePanel控件内的任何回发控件都将导致异步回发并刷新面板的内容。但是,也可以配置页上的其他控件来刷新UpdatePanel控件。可以通过为UpdatePanel控件定义触发器来做到这一点。触发器是一类绑定,用于指定使面板更新的回发控件和事件。当引发触发器控件的指定事件(例如,按钮的Click事件)时,将刷新更新面板。
使用UpdatePanel控件的Triggers元素内的asp:AsyncPostBackTrigger元素定义触发器。如果在Visual Studio中编辑页面,则可以使用【UpdatePanelTrigger集合编辑器】对话框创建触发器。
触发器的控件事件是可选的。如果不指定事件,则触发器事件是控件的默认事件。例如,对于Button控件,默认事件是Click事件。
【范例1】
向页面中添加一个ScriptManager和一个UpdatePanel控件,分别在UpdatePanel控件内部和UpdatePanel控件外部添加一个按钮,在UpdatePanel控件外部添加一个标签,并定义页面的加载事件,判断页面是否是第一次加载。
(1)若页面是第一次加载,则标签的标题是“页面首次加载”。
(2)若页面不是第一次加载,则标签的标题是“感谢再次光临!”。
省略控件的添加步骤,页面加载事件代码如下。
protected void Page_Load(object sender, EventArgs e) { if (! Page.IsPostBack) //页面是否首次加载 { num.Text = "页面首次加载"; } else //页面非首次加载 { num.Text = "感谢再次光临!"; } }
运行该页面,单击UpdatePanel控件内的按钮,页面没有变化,标签的标题是“页面首次加载”;而单击UpdatePanel控件外的按钮,标签的标题被修改为“感谢再次光临!”。可见UpdatePanel控件内的按钮只是进行了局部的更新,而UpdatePanel控件外的按钮可进行整页的更新。
13.3.3 异步回发中的应用限制
并不是所有的控件、方法和属性都支持页面的异步更新,其应用限制主要表现在三个方面:不支持异步更新的ASP.NET控件、不支持异步更新的Web控件、不支持异步更新的属性和方法。以下分别介绍不支持异步更新的控件、方法和属性。
1.不支持异步更新的ASP.NET控件
下面的ASP.NET控件与部分页更新不兼容,因此不应在UpdatePanel控件内使用。
(1)处于多种情况下的TreeView控件。一种情况是启用了不是异步回发的一部分的回调。另一种情况是将样式直接设置为控件属性,而不是通过使用对CSS样式的引用来隐式设置控件的样式。还有一种情况是EnableClientScript属性为false(默认值为true)。另外,还有一种情况是在异步回发之间更改了EnableClientScript属性的值。
(2)Menu控件(将样式直接设置为控件属性,而不是通过使用对CSS样式的引用来隐式设置控件的样式时)。
(3)FileUpload和HtmlInputFile控件(当它们作为异步回发的一部分用于上载文件时)。
(4)GridView和DetailsView控件(当它们的EnableSortingAndPagingCallbacks属性设置为true时)。默认值为false。
(5)Login、PasswordRecovery、ChangePassword和CreateUserWizard控件(其内容尚未转换为可编辑的模板)。
(6)Substitution控件。
若要在UpdatePanel控件内使用FileUpload或HtmlInputFile控件,需要将提交文件的回发控件设置为面板的PostBackTrigger控件。仅可以在回发方案中使用FileUpload和HtmlInputFile控件。
所有其他控件都可以在UpdatePanel控件内发挥作用。不过在某些情况下,控件在UpdatePanel控件内可能不会按预期方式工作。这些情况包括:
(1)通过调用ClientScriptManager控件的注册方法注册脚本。
(2)在该控件呈现过程中直接呈现脚本或标记,例如,通过调用Write()方法。
如果该控件调用ClientScriptManager控件的脚本注册方法,则也许能够改用ScriptManager控件相应的脚本注册方法。在此情况下,该控件可以在UpdatePanel控件内工作。
2.不支持异步更新的Web控件
Web控件是一组集成控件,用于创建网站使最终用户可以直接从浏览器修改网页的内容、外观和行为。可以在UpdatePanel控件内使用Web控件,但具有以下限制。
(1)每个WebPartZone控件都必须在同一UpdatePanel控件内。例如,页上不能具有两个带有各自的WebPartZone控件的UpdatePanel控件。
(2)WebPartManager控件管理Web部件控件的所有客户端状态信息。它必须在页面上的最外部的UpdatePanel控件内。
(3)不能通过使用异步回发导入或导出Web控件(执行此任务需要FileUpload控件,该控件不能与异步回发一起使用)。默认情况下,导入Web控件将执行完全回发。
(4)在异步回发过程中,不能添加或修改Web部件控件的样式。
3.不支持异步更新的属性和方法
在异步回发过程中,不支持在页面上设置默认回发按钮的以下方案。
(1)在异步回发过程中以编程方式更改DefaultButton。
(2)在异步回发过程中,当Panel控件不在UpdatePanel控件内部时以编程方式更改DefaultButton。
仅在回发方案(不包括异步回发方案)下才支持HttpResponse类的以下方法:BinaryWrite()、Clear()、ClearContent()、ClearHeaders()、Close()、End()、Flush()、TransmitFile()、Write()、WriteFile()和WriteSubstitution()。
13.3.4 UpdateProgress
使用UpdateProgress控件可以提供有关部分页呈现进度的反馈。对于回发或初始页呈现,不显示UpdateProgress控件内容。
页面可以包含多个UpdateProgress控件。每个控件都可以与不同的UpdatePanel控件关联。此外,还可以使用一个UpdateProgress控件,并将它与页上的所有UpdatePanel控件关联。
UpdateProgress控件根据回发所源于的位置以及是否设置UpdateProgress控件的AssociatedUpdatePanelID属性,来呈现显示或隐藏的div元素。
通过设置UpdateProgress控件的AssociatedUpdatePanelID属性,将UpdateProgress控件与UpdatePanel控件关联。当回发事件源于UpdatePanel控件内部时,会显示所有关联的UpdateProgress控件。如果没有设置AssociatedUpdatePanelID属性,则UpdateProgress控件会为源于任何UpdatePanel控件内部的任何异步回发显示进度。还会为充当面板触发器的任何控件显示进度。
AssociatedUpdatePanelID属性对UpdateProgress控件行为具有以下影响。
(1)如果没有设置AssociatedUpdatePanelID属性,则为以下回发显示UpdateProgress控件:源于任何UpdatePanel控件内部的回发;源于充当任何UpdatePanel控件的异步触发器的控件的回发。
(2)如果将AssociatedUpdatePanelID属性设置为UpdatePanel控件ID,则会为源于关联UpdatePanel控件内部的回发显示UpdateProgress控件。
(3)如果将AssociatedUpdatePanelID属性设置为不存在的控件,则永远不会显示UpdateProgress控件。
(4)如果将UpdatePanel控件的ChildrenAsTriggers属性设置为false,而回发源于UpdatePanel控件内部,则仍会显示任何关联的UpdateProgress控件。
使用ProgressTemplate属性可以指定由UpdateProgress控件显示的消息。如果ProgressTemplate属性为空,则在显示UpdateProgress控件时不会显示任何内容。
UpdateProgress控件可以位于其他UpdatePanel控件的内部或外部。UpdateProgress控件模板的显示与UpdateProgress控件所在的位置无关。在嵌套的UpdatePanel控件中,子面板位于父面板之内。在此情况下,源于子面板内部的回发会导致显示出与子面板和父面板关联的所有UpdateProgress控件。如果回发源于父面板的即时子控件,则只显示与父面板关联的UpdateProgress控件。
默认情况下,UpdateProgress控件会在显示其内容之前等待0.5s(500ms)。在异步回发的速度很快时,这有助于防止控件闪烁。通过设置DisplayAfter属性可指定延迟。
如果需要在显示UpdateProgress控件时进行更精细的控制,则可为PageRequestManager类的beginRequest和endRequest事件提供客户端脚本。在beginRequest事件处理程序中,可显示表示UpdateProgress控件的DOM元素。在endRequest事件处理程序中,可隐藏该元素。
在下列情况下,必须提供客户端脚本才能在更新目标UpdatePanel控件时显示UpdateProgress控件。
(1)将来自控件的回发注册为面板的异步回发触发器,并且页面上存在UpdateProgress控件。但是,AssociatedUpdatePanelID属性未设置为面板的ID。
(2)通过使用ScriptManager控件的RegisterAsyncPostBackControl方法将来自控件的回发注册为异步回发控件。