Over the last few weeks since MS Ajax Beta rolled around I’ve been getting a number of reports of the wwHoverPanel control running into some problems when running in combination with MS Ajax. The controls themselves don’t interfere with MS AJAX directly, but if you’re sticking the controls inside of an AJAX UpdatePanel() there’s a problem as the script code that the controls spit out don’t get properly generated into the callback generated updates. With the script code missing the controls still work but exhibit some unexpected behaviors. For example a hover panel placed into an update panel will lose it’s positioning in many cases and instead of popping up at the current mouse cursor position will pop up at the border of the container control it lives in. The problem is that Microosft decided in MS AJAX Beta to go with a completely separate script generation engine which is driven through the ScriptManager control. The MS Ajax ScriptManager mimics many of the ClientScript object’s methods, but provides them as static methods (thankfully! without that we’d be really screwed). So methods like RegisterClientScriptBlock, ResgisterClientScriptResources – anything that deals with getting script code into the page have related static methods in ScriptManager. The ScriptManager methods pass in the Control as an additional first parameter but otherwise mimic the existing ClientScriptManager. This new behavior puts existing controls into a bind though – if code uses ClientScriptManager then UpdatePanels will not be able to see the script code (if it needs updating in a callback). But at the same time the control developer can’t make the assumption that the MS Ajax ScriptManager actually exists. The end result of all of this is that it’s not exactly straight forward to deal with this mismatch and what needs to happen is that a wrapper object needs to be created that can decide which control to use. The wrapper needs to deal with deciding whether MS Ajax is available in the application and if it is, using Reflection to access the ScriptManager to write out any script code. I can’t take credit for this though: Eilon Lipton posted about this issue a while back and his code really was what I needed to get this off the ground, I just wrapped the thing up into a ClientScriptProxy object that I used on a handful of controls. I basically added a handful of the ClientScript methods that I use in my applications. Here’s the class: [*** code updated: 12/12/2006 from comments *** ] /// <summary> /// This is a proxy object for the Page.ClientScript and MS Ajax ScriptManager /// object that can operate when MS Ajax is not present. Because MS Ajax /// may not be available accessing the methods directly is not possible /// and we are required to indirectly reference client script methods through /// this class. /// /// This class should be invoked at the Controls start up and be used /// to replace all calls Page.ClientScript. Scriptmanager calls are made /// through Reflection /// </summary> public class ClientScriptProxy { private static Type scriptManagerType = null; // *** Register proxied methods of ScriptManager private static MethodInfo RegisterClientScriptBlockMethod; private static MethodInfo RegisterStartupScriptMethod; private static MethodInfo RegisterClientScriptIncludeMethod; private static MethodInfo RegisterClientScriptResourceMethod; //private static MethodInfo RegisterPostBackControlMethod; //private static MethodInfo GetWebResourceUrlMethod; ClientScriptManager clientScript; /// <summary> /// Determines if MsAjax is available in this Web application /// </summary> public bool IsMsAjax { get { if (scriptManagerType == null) CheckForMsAjax(); return _IsMsAjax; } } private static bool _IsMsAjax = false; public bool IsMsAjaxOnPage { get { return _IsMsAjaxOnPage; } } private bool _IsMsAjaxOnPage = false; /// <summary> /// Current instance of this class which should always be used to /// access this object. There are no public constructors to /// ensure the reference is used as a Singleton. /// </summary> public static ClientScriptProxy Current { get { return ( HttpContext.Current.Items[“__ClientScriptProxy”] ?? (HttpContext.Current.Items[“__ClientScriptProxy”] = new ClientScriptProxy(HttpContext.Current.Handler as Page))) as ClientScriptProxy; } } /// <summary> /// Base constructor. Pass in the page name so we can pick up /// the stock the /// </summary> /// <param name=”CurrentPage”></param> protected ClientScriptProxy(Page CurrentPage) { this.clientScript = CurrentPage.ClientScript; } /// <summary> /// Checks to see if MS Ajax is registered with the current /// Web application. /// /// Note: Method is static so it can be directly accessed from /// anywhere /// </summary> /// <returns></returns> public static bool CheckForMsAjax() { scriptManagerType = Type.GetType(“Microsoft.Web.UI.ScriptManager, Microsoft.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35”, false); if (scriptManagerType != null) { _IsMsAjax = true; return true; } _IsMsAjax = false; return false; } /// <summary> /// Registers a client script block in the page. /// </summary> /// <param name=”control”></param> /// <param name=”type”></param> /// <param name=”key”></param> /// <param name=”script”></param> /// <param name=”addScriptTags”></param> public void RegisterClientScriptBlock(Control control, Type type, string key, string script, bool addScriptTags) { if (this.IsMsAjax) { if (RegisterClientScriptBlockMethod == null) RegisterClientScriptBlockMethod = scriptManagerType.GetMethod(“RegisterClientScriptBlock”); RegisterClientScriptBlockMethod.Invoke(null, new object[5] { control, type, key, script, addScriptTags }); } else this.clientScript.RegisterClientScriptBlock(type, key, script, addScriptTags); } /// <summary> /// Registers a startup code snippet that gets placed at the bottom of the page /// </summary> /// <param name=”control”></param> /// <param name=”type”></param> /// <param name=”key”></param> /// <param name=”script”></param> /// <param name=”addStartupTags”></param> public void RegisterStartupScript(Control control, Type type, string key, string script, bool addStartupTags) { if (this.IsMsAjax) { if (RegisterStartupScriptMethod == null) RegisterStartupScriptMethod = scriptManagerType.GetMethod(“RegisterStartupScript”); RegisterStartupScriptMethod.Invoke(null, new object[5] { control, type, key, script, addStartupTags }); } else this.clientScript.RegisterStartupScript(type, key, script, addStartupTags); } /// <summary> /// Registers a script include tag into the page for an external script url /// </summary> /// <param name=”control”></param> /// <param name=”type”></param> /// <param name=”key”></param> /// <param name=”url”></param> public void RegisterClientScriptInclude(Control control, Type type, string key, string url) { if (this.IsMsAjax) { if (RegisterClientScriptIncludeMethod == null) RegisterClientScriptIncludeMethod = scriptManagerType.GetMethod(“RegisterClientScriptInclude”); RegisterClientScriptIncludeMethod.Invoke(null, new object[4] { control, type, key, url }); } else this.clientScript.RegisterClientScriptInclude( type, key, url); } /// <summary> /// Adds a script include tag into the page for WebResource. /// </summary> /// <param name=”control”></param> /// <param name=”type”></param> /// <param name=”resourceName”></param> public void RegisterClientScriptResource(Control control, Type type, string resourceName) { if (this.IsMsAjax) { if (RegisterClientScriptResourceMethod == null) RegisterClientScriptResourceMethod = scriptManagerType.GetMethod(“RegisterClientScriptResource”); RegisterClientScriptResourceMethod.Invoke(null, new object[3] { control, type, resourceName }); } else this.clientScript.RegisterClientScriptResource(type,resourceName); } public string GetWebResourceUrl(Control control, Type type, string resourceName) { //if (this.IsMsAjax) //{ // if (GetWebResourceUrlMethod == null) // GetWebResourceUrlMethod = scriptManagerType.GetMethod(“GetScriptResourceUrl”); // return GetWebResourceUrlMethod.Invoke(null, new object[2] { resourceName, control.GetType().Assembly }) as string; //} //else return this.clientScript.GetWebResourceUrl(type, resourceName); } } The code basically checks to see whether the MS Ajax assembly can be accessed as a type and if so assumes MS Ajax is installed. This is not quite optimal – it’d be better to know whether a ScriptManager is actually being used on the current page, but without scanning through all controls (slow) I can’t see a way of doing that easily. The control caches each of the MethodInfo structures to defer some of the overhead in making the Reflection calls to the ScriptManager methods. I don’t think that Reflection here is going to cause much worry about overhead unless you have a LOT of calls to these methods (I suppose it’s possible if you have lots of resources – think of a control like FreeTextBox for example). Even then the Reflection overhead is probably not worth worrying about. To use this class all calls to ClientScript get replaced with call this class instead. So somewhere during initialization of the control I add: protected override void OnInit(EventArgs e) { this.ClientScriptProxy = ClientScriptProxy.Current; base.OnInit(e); } And then to use it: this.ClientScriptProxy.RegisterClientScriptInclude(this,this.GetType(), ControlResources.SCRIPTLIBRARY_SCRIPT_RESOURCE, this.ResolveUrl(this.ScriptLocation)); Notice the first parameter is the control instance (typically this) just like the ScriptManager call, so there will be a slight change of parameters when changing over from ClientScript code. Once I added this code to my controls the problems with UpdatePanel went away and it started rendering properly again even with the controls hosted inside of the UpdatePanels.
updatepanel和自定义控件中的客户端脚本_asp.net技巧
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » updatepanel和自定义控件中的客户端脚本_asp.net技巧
相关推荐
-      对.net framework 反射的反思_asp.net技巧
-      .net3.5和vs2008中的asp.net ajax_asp.net技巧
-      使用asp.net ajax框架扩展html map控件_asp.net技巧
-      asp.net应用程序资源访问安全模型_asp.net技巧
-      photoshop初学者轻松绘制螺旋漩涡特效_photoshop教程
-      photoshop通道结合图层模式抠狗尾巴草_photoshop教程
-      web.config详解+asp.net优化_asp.net技巧
-      asp.net中多彩下拉框的实现_asp.net技巧