网络编程 | 站长之家 | 网页制作 | 图形图象 | 操作系统 | 冲浪宝典 | 软件教学 | 网络办公 | 邮件系统 | 网络安全 | 认证考试 | 系统进程
Firefox | IE | Maxthon | 迅雷 | 电驴 | BitComet | FlashGet | QQ | QQ空间 | Vista | 输入法 | Ghost | Word | Excel | wps | Powerpoint
asp | .net | php | jsp | Sql | c# | Ajax | xml | Dreamweaver | FrontPages | Javascript | css | photoshop | fireworks | Flash | Cad | Discuz!
当前位置 > 网站建设学院 > 网络编程 > ASP.NET技巧
Tag:注入,存储过程,分页,安全,优化,xmlhttp,fso,jmail,application,session,防盗链,stream,无组件,组件,md5,乱码,缓存,加密,验证码,算法,cookies,ubb,正则表达式,水印,索引,日志,压缩,base64,url重写,上传,控件,Web.config,JDBC,函数,内存,PDF,迁移,结构,破解,编译,配置,进程,分词,IIS,Apache,Tomcat,phpmyadmin,Gzip,触发器,socket
网络编程:ASP教程,ASP.NET教程,PHP教程,JSP教程,C#教程,数据库,XML教程,Ajax,Java,Perl,Shell,VB教程,Delphi,C/C++教程,软件工程,J2EE/J2ME,移动开发
本月文章推荐
.Asp.net对文件夹和文件的操作类.
.如何在ASP.NET中获取随机生成的c.
.关于Asp.net中使用以下代码导出E.
.asp.net 生成图片验证码.
.ASP.NET图象处理详解(1).
.ASP.NET AJAX正式版带来的Valida.
..Net中如何操作IIS(原理篇).
.ASP.NET 2.0 X64的奇怪问题.
.在VS2003+IE7.0下调试asp.net权限.
.何时.NET中AppDomain会回收? .
..net2.0邮件发送代码.
.同时对多个文件进行大量写操作对.
.如何在asp.net2.0下面使用基于数.
.DataGrid实例(简单易懂,无复杂.
.在.net中使用GDI+来提高gif图片的.
.ASP.NET技巧:为Blog打造个性日历.
.asp.net 2.0中加密web.config.
.net中统一的存储过程调用方法.
.深入聊聊Array的sort方法的使用技.
.将Web站点下的绝对路径转换为虚拟.

UpdatePanel和自定义控件中的客户端脚本

发表日期:2006-12-18


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 Control's 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.

上一篇:在VS2003+IE7.0下调试asp.net权限问题的解决办法 人气:4031
下一篇:MSBuild, NAnt, NUnit, MSTest所带来的不爽 人气:4458
浏览全部UpdatePanel的内容 Dreamweaver插件下载 网页广告代码 祝你圣诞节快乐 2009年新年快乐