在自定义控件中,ASP.NET AJAX支持

分享于 

13分钟阅读

Web开发

  繁體 雙語

介绍

本文对于希望更新它的控件以便在 ASP.NET AJAX中正确工作的任何定制组件开发人员来说都很有用。 首先,我们将描述此类定制过程中出现的最常见问题,然后为这些问题提出解决方案。

问题描述

假设你为 ASP.NET (。比如,有一些改进的编辑框) 开发了一些可视化控件。 让我们假设你的控件使用一些客户端脚本来实现这些"改进"的行为。

问题是:你的控件是否能很好地使用 ASP.NET AJAX增强功能? 或者更精确:如果有人将你的控件放在 UpdatePanel 中,以启用部分页面更新? 一般答案是: 我告诉你为什么。 如果控件使用一些客户端脚本,那么应该使用 ClientScriptManager 类的RegisterClientScriptBlock 方法在 PreRender 阶段上对这些脚本进行 register。 通常,它看起来与下面的代码相似:

protectedoverridevoid OnPreRender(EventArgs e) {
 base.OnPreRender(e);
 string scriptCode = "<script type="text/javascript">n<!--n";
. . . . . . . . 
 //script code definition. . . . . . . . 
 scriptCode += "//-->n</script>";
 Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "MyScriptName",
 scriptCode);
}

这里代码将正常运行,并且你的脚本将包含在页面的正常页面呈现中。 它甚至在 UpdatePanel 中工作,但只有当组件是 static的时候,如果它被放在页面上,并在第一页创建。 但是,如果组件放置在 UpdatePanel 中,并且根据某些异步更新而动态创建,那么这样一段代码将无法工作。

解决办法是什么呢

要解决这个问题,需要具备以下能力:

  • 确定我们的控件是否在 UpdatePanel 中;
  • 确定当前 postback 是否在部分呈现模式下执行,或者是通常的同步 postback ;
  • 在异步 postback 期间 register 客户端脚本的一种方法。

此外,实现所有描述特性的代码不能对 ASP.NET AJAX汇编( System.Web.Extensions.dll ) 使用 static 链接,因为我们的控件不能在没有安装 ASP.NET AJAX的网站上工作。

前两个特性非常容易实现。 我们只需要查找控制父级,并检查其中是否有 UpdatePanel 控件。 对于第二个任务,我们还需要检查找到的UpdatePanelIsInPartialRendering 属性。 请记住我们对 static 链接的限制: 所以我们只能通过通常的方式访问属性,但需要使用 System.Reflection 命名空间中类提供的能力。

对于第三个问题(。在部分更新中注册的客户端脚本): 我们应该使用 ScriptManager 对象的RegisterClientScriptXXX 方法,该对象应该包含在支持 ASP.NET AJAX的每个页面上。 所以,我们需要先在页面上找到那个对象,然后调用必要的方法。 唯一的问题( 再次): 我们不能直接这样做。 我们应该先加载 ASP.NET AJAX组件,然后找到 ScriptManager 对象,然后使用反射调用该对象的必要方法。

下面是实现所有描述任务的代码( AJAX类)。 这里类的所有方法都定义为 static 因此,我们不需要创建这个类的实例来调用它们。

using System;using System.Collections.Generic;using System.Text;using System.Web.UI;namespace Korzh.WebControls {
 ///<summary>/// Represents different procedures for ASP.NET AJAX extentions support///</summary>publicclass Ajax {
 ///<summary>/// Determines whether the specified control is inside UpdatePanel///</summary>///<paramname="control">The control.</param>///<returns>///<c>true</c> if the specified control is inside UpdatePanel; otherwise,///<c>false</c>.///</returns>publicstaticbool IsControlInsideUpdatePanel(Control control) {
 Control parent = control.Parent;
 while (parent!= null) {
 if (parent.GetType().FullName.Equals("System.Web.UI.UpdatePanel"))
 returntrue;
 parent = parent.Parent;
 }
 returnfalse; 
 }
 ///<summary>/// Determines whether the specified control is in partial rendering.///</summary>///<paramname="control">The control.</param>///<returns>///<c>true</c> if the specified control is in partial rendering; otherwise,///<c>false</c>.///</returns>publicstaticbool IsControlInPartialRendering(Control control) {
 Control parent = control.Parent;
 while (parent!= null) {
 if (parent.GetType().FullName.Equals("System.Web.UI.UpdatePanel")) {
 System.Reflection.PropertyInfo propInfo =
 parent.GetType().GetProperty("IsInPartialRendering");
 if (propInfo!= null) 
 return (bool)propInfo.GetValue(parent, null);
 elsereturnfalse;
 }
 parent = parent.Parent;
 }
 returnfalse;
 }
 ///<summary>/// Determines whether the current postback is being executed in/// partial-rendering mode.///</summary>///<paramname="page">The page object.</param>///<returns>///<c>true</c> if the current postback is being executed in/// partial-rendering mode; otherwise, <c>false</c>.///</returns>publicstaticbool IsInAsyncPostBack(Page page) {
 object scriptManager = FindScriptManager(page);
 if (scriptManager!= null) {
 System.Type smClass = GetScriptManagerType(scriptManager);
 System.Reflection.PropertyInfo propInfo = smClass.GetProperty(
 "IsInAsyncPostBack");
 if (propInfo!= null)
 return (bool)propInfo.GetValue(scriptManager, null);
 elsereturnfalse;
 }
 returnfalse;
 }
 privatestaticbool ObjectIsInheritedFrom(Object obj, string fullTypeName) {
 Type type = obj.GetType();
 while (type!= null) {
 if (type.FullName.Equals(fullTypeName)) returntrue;
 type = type.BaseType;
 }
 returnfalse;
 }
 privatestaticobject FindScriptManager(Control parent) {
 foreach (Control control in parent.Controls) {
 if (ObjectIsInheritedFrom(control, "System.Web.UI.ScriptManager"))
 return control;
 object result = FindScriptManager(control);
 if (result!= null) return result;
 }
 returnnull;
 }
 privatestatic System.Reflection.Assembly ajaxAssembly = null;
 privatestaticvoid LoadAjaxAssembly() {
 if (ajaxAssembly == null) {
 ajaxAssembly = System.Reflection.Assembly.LoadFrom(
 "System.Web.Extensions.dll");
 }
 }
 privatestatic System.Type GetTypeFromAjaxAssembly(string className) {
 LoadAjaxAssembly();
 if (ajaxAssembly!= null)
 return ajaxAssembly.GetType(className);
 elsereturnnull;
 }
 privatestatic Type GetScriptManagerType(Object obj) {
 Type type = obj.GetType();
 while (type!= null) {
 if (type.FullName.Equals("System.Web.UI.ScriptManager")) return type;
 type = type.BaseType;
 }
 returnnull;
 }
 ///<summary>/// Registers a client script block which will be rendered on each/// asynchronous postback./// Works only if ScriptManager control is existed on the page. Otherwise/// does nothing.///</summary>///<paramname="page">The Page object that is registering the client/// script block.</param>///<paramname="type">The type of the client script block. </param>///<paramname="key">The string that uniquely identifies the/// script block.</param>///<paramname="script">A string that contains the script.</param>///<paramname="addScriptTags">/// A Boolean value that indicates whether to enclose the script/// block in <script> tags.///</param>publicstaticvoid RegisterClientScriptBlock(Page page, Type type,
 string key, string script, bool addScriptTags) {
 object scriptManager = FindScriptManager(page);
 if (scriptManager!= null) {
 System.Type smClass = GetScriptManagerType(scriptManager);
 if (smClass!= null) {
 Object[] args = new Object[] { page, type, key, script,
 addScriptTags };
 smClass.InvokeMember("RegisterClientScriptBlock", 
 System.Reflection.BindingFlags.Static |
 System.Reflection.BindingFlags.Public | 
 System.Reflection.BindingFlags.InvokeMethod,
 null, null, args);
 }
 }
 }
 ///<summary>/// Registers a script file which to be rendered each time an asynchronous/// postback occurs./// Works only if ScriptManager control is existed on the page. Otherwise/// does nothing.///</summary>///<paramname="page">The Page object that is registering the client/// script file.</param>///<paramname="type">The type of the client script file.</param>///<paramname="key">The string that uniquely identifies the script file.</param>///<paramname="url">The URL that points to the script file.</param>publicstaticvoid RegisterClientScriptInclude(Page page, Type type,
 string key, string url) {
 object scriptManager = FindScriptManager(page);
 if (scriptManager!= null) {
 System.Type smClass = GetScriptManagerType(scriptManager);
 if (smClass!= null) {
 Object[] args = new Object[] { page, type, key, url };
 smClass.InvokeMember("RegisterClientScriptInclude", 
 System.Reflection.BindingFlags.Static |
 System.Reflection.BindingFlags.Public | 
 System.Reflection.BindingFlags.InvokeMethod,
 null, null, args);
 }
 }
 }
 ///<summary>/// Registers a script file which to be rendered each time an asynchronous/// postback occurs./// Works only if ScriptManager control is existed on the page. Otherwise/// does nothing.///</summary>///<paramname="page">The page.</param>///<paramname="type">The type of the client script file.</param>///<paramname="resourceName">The name of resource that contains the/// script file.</param>publicstaticvoid RegisterClientScriptResource(Page page, Type type,
 string resourceName) {
 object scriptManager = FindScriptManager(page);
 if (scriptManager!= null) {
 System.Type smClass = GetScriptManagerType(scriptManager);
 if (smClass!= null) {
 Object[] args = new Object[] { page, type, resourceName };
 smClass.InvokeMember("RegisterClientScriptResource",
 System.Reflection.BindingFlags.Static |
 System.Reflection.BindingFlags.Public |
 System.Reflection.BindingFlags.InvokeMethod,
 null, null, args);
 }
 }
 }
 }
}

使用这个类,我们可以从第一章修改代码中的OnPreRender 方法:

protectedoverridevoid OnPreRender(EventArgs e) {
 base.OnPreRender(e);
 string scriptCode = "<script type="text/javascript">n<!--n";
. . . . . . . . 
 //script code definition. . . . . . . . 
 scriptCode += "//-->n</script>";
 //register our client script for usual post-back//(will do nothing in case of partial udpate) Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "MyScriptName",
 scriptCode);
 //register our script during asynchronous postback//this code will just do nothing if there is no ASP.NET AJAX installedif (Ajax.IsControlInUpdatePanel(this) && Ajax.IsInAsyncPostBack(Page))
 Ajax.RegisterClientScriptBlock(Page, this.GetType(), "MyScriptName",
 scriptCode, false)
}

相关文章