分享
 
 
 

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

王朝other·作者佚名  2008-05-31
窄屏简体版  字體: |||超大  

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.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有