2010-10-07 62 views
1

我写了一个简单的控件,它实现了ScriptControl。这是jQuery框架持有人:ASP.NET ScriptManager输出不包含在ASP.NET部分缓存中(ascx)

/// <summary> 
/// Generic control with client behavior handled via jQuery 
/// </summary> 
public abstract partial class JQControl : ScriptControl, INamingContainer 
{ 
    /// <summary> 
    /// Client method to be called after jQuery initialization 
    /// </summary> 
    [PersistenceMode(PersistenceMode.InnerProperty)] 
    public JQRaw AfterInit 
    { 
     get; 
     set; 
    } 

    /// <summary> 
    /// Client method to be called before jQuery initialization 
    /// </summary> 
    [PersistenceMode(PersistenceMode.InnerProperty)] 
    public JQRaw PreInit 
    { 
     get; 
     set; 
    } 

    /// <summary> 
    /// Any data to initialize the control with (name-value pairs) 
    /// </summary> 
    public IDictionary<string, object> InitData 
    { 
     get; set; 
    } 

    /// <summary> 
    /// Authorization templates to be registered and used by privilege manager 
    /// </summary> 
    public IDictionary<string, AuthorizationTemplate> AuthorizationTemplates 
    { 
     get; set; 
    } 

    /// <summary> 
    /// If ThemePath is specified, this css file will be looked for and loaded from the theme folder 
    /// </summary> 
    protected string ThemeCssName 
    { 
     get; set; 
    } 

    private string _themePath; 

    /// <summary> 
    /// Specifies path to look for custom css and images to enable theming. 
    /// </summary> 
    public string ThemePath 
    { 
     get 
     { 
      return _themePath == null ? DefaultThemeHelper.ThemeName : ResolveClientUrl(_themePath); 
     } 
     set 
     { 
      _themePath = value; 
     } 
    } 

    /// <summary> 
    /// Collection of streamed javascript files 
    /// </summary> 
    private readonly List<ScriptReference> scriptRefs = new List<ScriptReference>(); 

    /// <summary> 
    /// Collection of streamed stylesheet files 
    /// </summary> 
    private readonly List<string> cssRefs = new List<string>(); 

    protected override void OnInit(EventArgs e) 
    { 
     base.OnInit(e); 
     FillScriptReferences(); 
    } 

    protected override void OnPreRender(EventArgs e) 
    { 
     base.OnPreRender(e); 

    } 
    protected bool useDynamicCss = true; 




    private bool dynamicCssEnabled; 
    protected void EnableDynamicCss() 
    { 
     if(!dynamicCssEnabled) 
     { 
      //enable dynamic css loading 
      addScriptReference(typeof(JQControl), "LWM.Implementation.Controls.DynamicStylesheet.css.js"); 
      dynamicCssEnabled = true; 
     } 
    } 

    protected virtual void FillScriptReferences() 
    { 
     Type t = typeof(JQControl); 
     addScriptReference(t, "LWM.Implementation.Controls.JScripts.Jquery.js"); 
     addScriptReference(t, "LWM.Implementation.Controls.JScripts.ExtendJQuery.js"); 
     addScriptReference(t, "LWM.Implementation.Controls.JScripts.ExtendAJAXDotNet.js"); 
     addScriptReference(t, "LWM.Implementation.Controls.JQ.ChainRequests.js"); 
     addScriptReference(t, "LWM.Implementation.Controls.JScripts.jquery.jcache.js"); 
     addScriptReference(t, "LWM.Implementation.Controls.JScripts.jquery.cookie.js"); 
     addScriptReference(t, "LWM.Implementation.Controls.JScripts.jquery.offset.js"); 
     //if ((_themePath != null && ThemeCssName != null)) 
     { 
      EnableDynamicCss();     
     } 
    } 

    //added to render automatically assigned id, otherwise escaped 
    protected override void AddAttributesToRender(HtmlTextWriter writer) 
    { 
     const string extCss = "jqcontrol"; 
     this.CssClass = this.CssClass != null ? this.CssClass + " " + extCss : extCss; 

     base.AddAttributesToRender(writer); 
     writer.AddAttribute(HtmlTextWriterAttribute.Id, ClientID); 
     //writer.AddAttribute(HtmlTextWriterAttribute.Class, CssClass); 
    } 

    /// <summary> 
    /// Ataches an embedded script refernnce using its full name 
    /// </summary> 
    /// <param name="name">Name of the reference</param> 
    /// <param name="useBaseClassAssembly">True if using base class assembly</param> 
    protected void AttachScriptRefernceByName(string name, bool useBaseClassAssembly) 
    { 
     //current type 
     Type type = this.GetType(); 
     if (useBaseClassAssembly) 
     { 
      //base type 
      type = type.BaseType; 
     } 
     addScriptReference(type, name); 
    } 

    private void _addCssReference(Type type, string name) 
    { 
     string assembly = type.Assembly.FullName; 
     Type t = null; 
     if (BoostHelper.AdjustResourceParts(this, type.Assembly, ref assembly, ref name, ref t)) 
     { 
      // LoggerHelper.LogInfo(String.Format("CSS init with- Client Script:{0}, Type:{1}, Name:{2} ", this.Page.ClientScript.ToString(),t.ToString(),name),"LWMSiteResourceBooster"); 

      var sr = new DynamicStylesheetScriptReference(this.Page.ClientScript, t, new[] { name }); //(name, assembly); 

      if (!scriptRefs.Contains(sr)) 
      { 
       scriptRefs.Add(sr); 
      } 
     } 
     else 
     { 
      string url = name; // GetEmbeddedURL(type, name); 
      if (!cssRefs.Contains(url)) 
      { 
       cssRefs.Add(url); 
      } 
     } 
    } 

    //protected void addCssReference(string name, Type type) 
    //{ 
    // _addCssReference(type, name); 
    // if (cssRefs.Count > 0) 
    // { 
    //  scriptRefs.Add(new DynamicStylesheetScriptReference(this.Page.ClientScript, type, cssRefs.ToArray())); 
    //  cssRefs.Clear(); 
    // } 
    //} 

    protected void addCssReference(Type type, params string[] names) 
    { 
     if (names == null) return; 
     foreach (string name in names) 
     { 
      _addCssReference(type, name); 
     } 
     if(cssRefs.Count > 0) 
     { 
      scriptRefs.Add(new DynamicStylesheetScriptReference(this.Page.ClientScript, type, cssRefs.ToArray())); 
      cssRefs.Clear(); 
     } 
    } 


    protected void removeCssReference(Type type, string name) 
    { 
     //TODO 
     //if (cssRefs.Contains(url)) 
     //{ 
     // cssRefs.Remove(url); 
     //} 
    } 

    protected void addScriptReference(Type type, string name) 
    { 


     //full name of the current assembly    
     string assembly = type.Assembly.FullName; 
     Type t = null; 
     BoostHelper.AdjustResourceParts(this, type.Assembly, ref assembly, ref name, ref t); 
     var sr = new HumanReadableScriptReference(name, assembly); 
     if (!scriptRefs.Contains(sr)) 
     { 
      scriptRefs.Add(sr); 
     } 
    } 

    protected void removeScriptReference(Type type, string name) 
    { 
     //full name of the current assembly    
     string assembly = type.Assembly.FullName; 
     Type t = null; 
     BoostHelper.AdjustResourceParts(this, type.Assembly, ref assembly, ref name, ref t); 
     var sr = new HumanReadableScriptReference(name, assembly); 
     if (scriptRefs.Contains(sr)) 
     { 
      scriptRefs.Remove(sr); 
     } 
    } 

    private string _jqBreadCrumb; 

    /// <summary> 
    /// Unique jQuery pattern that identifies this control 
    /// </summary> 
    protected string JQBreadCrumb 
    { 
     get 
     { 
      if (_jqBreadCrumb == null) 
      { 
       //StringBuilder sb = new StringBuilder(); 
       //Control c = this; 
       Control c = this.NamingContainer; 
       //int step = 1; 
       while (c != null && c.ClientID != "__Page") 
       { 
        if (c is JQControl) // || step > 1) 
        { 
         _jqBreadCrumb = c.ClientID; 
         break; 
         //sb.Insert(0, " "); 
         //sb.Insert(0, "#" + c.ClientID); 
        } 
        c = c.NamingContainer; 
        //step++; 
       } 
       //_jqBreadCrumb = sb.ToString(); 
      } 
      return _jqBreadCrumb; 
     } 
    } 

    //regular expression to look for tokens 
    private static readonly Regex tokenRegex = new Regex(
     @"##(?<tokenName>[\w\:]+)" 
     ); 



    //actually replaces tokens 
    private string tokenReplacer(Match m, bool useContext) 
    { 
     //token found 
     string tokenName = m.Groups["tokenName"].Value; 
     string ctlName = null; 
     //check if we have a resource token 
     if (ResourceHelper.CheckStringForToken(tokenName)) 
     { 
      return "\"" + ResourceHelper.GetStringByToken(tokenName, ResourceType.Portal) + "\""; 
     } 
     switch (tokenName) 
     { 
      case "this": 
       //special case: seek for the current control 
       if (useContext) return "$(__$)"; 
       ctlName = "#" + this.ClientID; // JQBreadCrumb; 
       break; 
      case "parent": 
       //special case: seek for the direct parent control 
       ctlName = "#" + JQBreadCrumb; 
       // this.NamingContainer.ClientID; //NOTE: use parent breadcrumb here 
       break; 
      default: 
       //seek for the child control with the given name 
       if (!useContext) 
       { 
        Control ctl = getChildByName(tokenName); 
        if (ctl != null) ctlName = "#" + ctl.ClientID; 
       } 
       //else ctlName = "[id^='" + this.ClientID + "_']" + "[id$='_" + tokenName + "']:first"; 
       break; 
     } 
     if(ctlName != null) return "$(\"" + ctlName + "\")"; 
     if (!useContext) return "$(this)._cc('" + tokenName + "', '" + this.ClientID + "')"; 
     return "$(__$)._cc('" + tokenName + "')"; 
    } 

    private string tokenReplacerWithContext(Match m) 
    { 
     return tokenReplacer(m, true); 
    } 

    private string tokenReplacerWithoutContext(Match m) 
    { 
     return tokenReplacer(m, false); 
    } 

    protected virtual Control getChildByName(string name) 
    { 
     return this.Controls.Cast<Control>().SingleOrDefault(c => c.ID == name); 
    } 

    //regular expression to insert context holder 
    private static readonly Regex contextRegex = new Regex(
     @"^(\s*function\(\s*\)\s*{)", RegexOptions.Multiline 
     ); 

    private static int replacedNum; 
    private static string contextReplacer(Match m) 
    { 
     replacedNum++; 
     return "function() { var __$ = this; \r\n"; 
    } 

    /// <summary> 
    /// Substitue occurences of tokens of type ##[token] into corresponding jQuery calls 
    /// </summary> 
    /// <param name="callbackMethod">Callback method definition that contains tokens</param> 
    /// <param name="useContext">True if local context is to be used on the client</param> 
    protected void PrepareCallbackMethod(JQRaw callbackMethod, bool useContext) 
    { 
     if(useContext) 
     { 
      replacedNum = 0; 
      callbackMethod.JQRawContent = contextRegex.Replace(callbackMethod.JQRawContent, contextReplacer); 
      if(replacedNum == 0) useContext = false; 
     } 
     if (callbackMethod != null) 
     { 
      MatchEvaluator me; 
      if(useContext) me = tokenReplacerWithContext; 
      else me = tokenReplacerWithoutContext; 

      //find tokens in callback body and replace them 
      callbackMethod.JQRawContent = tokenRegex.Replace(callbackMethod.JQRawContent, me); 
     } 
    } 

    protected void PrepareCallbackMethod(JQRaw callbackMethod) 
    { 
     PrepareCallbackMethod(callbackMethod, false); 
    } 

    protected virtual void PrepareCallbackMethods(object @params) 
    { 
     foreach (PropertyInfo pi in @params.GetType().GetProperties().Where(
       p => p.PropertyType.Equals(typeof(JQRaw)) 
      )) 
     { 
      if (pi.GetCustomAttributes(typeof(CallbackMethodAttribute), false).Length > 0) 
      { 
       //property has the attribute: prepare 
       JQRaw pty = (JQRaw)pi.GetValue(@params, null); 
       if (pty != null && pty.JQRawContent != null) 
       { 
        PrepareCallbackMethod(pty); 
       } 
      } 
     } 
    } 

    /// <summary> 
    /// Returns the script files for the control 
    /// </summary> 
    /// <returns>Collection that contains ECMAScript (JavaScript) files that have been registered as embedded resources</returns> 
    protected override IEnumerable<ScriptReference> GetScriptReferences() 
    { 
     return scriptRefs; 
    } 

    private const string selfAlias = "__$"; 
    protected virtual string GetDescriptorSelector() 
    { 
     //return this.ClientID; 
     return selfAlias; 
    } 

    protected virtual IEnumerable<ScriptDescriptor> _getScriptDescriptors() 
    { 
     yield break; 
    } 

    //private const string afterInitTemplate = "function() {{ var _method = {0}; _method(); $('#{1}').trigger('_loadComplete'); }}"; 

    protected sealed override IEnumerable<ScriptDescriptor> GetScriptDescriptors() 
    { 
     var result = new List<ScriptDescriptor>(); 

     //yield return new JQSelfDescriptor(this.ClientID, selfAlias); 
     result.Add(new JQSelfDescriptor(this.ClientID, selfAlias)); 


     if (PreInit != null) 
     { 
      //to be executed before initialization 
      PrepareCallbackMethod(PreInit, true); 
      //yield return new JQDescriptor(GetDescriptorSelector(), "each", true, PreInit); 
      result.Add(new JQDescriptor(GetDescriptorSelector(), "each", true, PreInit)); 
     } 

     if(InitData != null) 
     { 
      foreach (string key in InitData.Keys) 
      { 
       //initialize with the given object as data 
       object data; 
       bool useStd = false; 
       if (InitData[key] is NativeContainer) 
       { 
        data = ((NativeContainer)InitData[key]).Content; 
        useStd = true; 
       } 
       else data = InitData[key]; 
       JQDescriptor jdesc = new JQDescriptor(GetDescriptorSelector(), "data", true, key, data); 
       if(useStd) jdesc.UseStandardSerializer = true; 
        //yield return jdesc; 
        result.Add(jdesc); 
      } 
     } 

     if (AuthorizationTemplates != null) 
     { 
      //register authorization templates 
      //yield return new JQDescriptor(GetDescriptorSelector(), "pm_registerAuthTemplates", true, AuthorizationTemplates); 
      result.Add(new JQDescriptor(GetDescriptorSelector(), "pm_registerAuthTemplates", true, AuthorizationTemplates)); 
     } 

     //enumerate overriden method results 
     foreach(ScriptDescriptor sd in _getScriptDescriptors()) 
     { 
      // yield return sd; 
      result.Add(sd); 
     } 

     if (AfterInit != null) 
     { 
      //to be executed after initialization 
      PrepareCallbackMethod(AfterInit, true); 
      //AfterInit.JQRawContent = String.Format(afterInitTemplate, AfterInit.JQRawContent, GetDescriptorSelector()); 
      //yield return new JQDescriptor(GetDescriptorSelector(), "each", true, AfterInit); 
      result.Add(new JQDescriptor(GetDescriptorSelector(), "each", true, AfterInit)); 
     } 

     if (ThemePath != null && ThemeCssName != null) 
     { 
      //load css file dynamically 
      string cssURL = VirtualURLHelper.Combine(ThemePath, ThemeCssName); 
      DynamicStylesheetDescriptor dsdesc = new DynamicStylesheetDescriptor(cssURL); 
      //yield return dsdesc; 
      result.Add(dsdesc); 
     } 

     if (cssRefs.Count > 0) 
     { 
      DynamicStylesheetDescriptor dsdesc = new DynamicStylesheetDescriptor(cssRefs); 
      //yield return dsdesc; 
      result.Add(dsdesc); 
     } 

     //final trigger 
     //yield return new JQDescriptor(GetDescriptorSelector(), "trigger", "_loadComplete"); 

     //yield break; 
     return result; 
    } 

    /// <summary> 
    /// Helper method to create URL to an embedded resource 
    /// </summary> 
    /// <param name="type">The type of the server-side resource</param> 
    /// <param name="resourceName">The name of the server-side resource</param> 
    /// <returns>The URL reference to the resource</returns> 
    protected string GetEmbeddedURL(Type type, string resourceName) 
    { 
     //get base URL 
     string url = Page.ClientScript.GetWebResourceUrl(type, resourceName); 
     //attach name of the resource 
     return url.Replace("?", "?name=" + resourceName + "&"); 
    } 
} 

我把它放在网页上到ascx控件: 页:'<%@页面语言= “C#” AutoEventWireup = “真” 代码隐藏= “p2.aspx.cs”继承= “LWM.Implementation.Portal.Sample.TestOutputCache.p2” %>

<%@注册的TagPrefix = “LWM” SRC = “〜/样品/ TestOutputCache/testControl2.ascx” 变量名= “TestControl2” % >

<LWM:TestControl2 ID="testCached" runat="server" /> 


</div> 
</form> 

'

ASCX:`<%@控制语言= “C#” AutoEventWireup = “真” 的CodeBehind = “testControl2.ascx.cs” 继承=“LWM.Implementation.Portal。 Sample.testControl2“%> <%@ OutputCache Duration =”600“VaryByParam =”None“%> <%@ Register TagPrefix =”Controls“Assembly =”LWM.Implementation.Controls“Namespace =”LWM.Implementation.Controls .JQComposite“%> 测试2 功能(EVT) {

 console.log("afterInit 2"); 
    } 
</AfterInit> 

`

此外,我使ascx控件缓存。当页面第一次加载一切ok,但页面从服务器缓存getting时,所有脚本引用丢失...

我搜索了很多,找不到任何想法。 所以,问题在于当从服务器缓存加载控件时,scriptmanager不会生成脚本引用。

回答

1

这是错误与OutputCaching和脚本管理器,从而正式为recognized by Microsoft

有解决方法脚本添加到手动的ScriptManager:

<asp:ScriptManager ID="ScriptManager1" runat="server"> 
     <Scripts> 
      <asp:ScriptReference Name="AjaxControlToolkit.Common.Common.js" Assembly="AjaxControlToolkit" /> 
      <asp:ScriptReference Name="AjaxControlToolkit.ExtenderBase.BaseScripts.js" Assembly="AjaxControlToolkit" /> 
      <asp:ScriptReference Name="AjaxControlToolkit.TextboxWatermark.TextboxWatermark.js" 
       Assembly="AjaxControlToolkit" /> 
     </Scripts> 
    </asp:ScriptManager> 
+0

微软链接似乎被打破或许可被拒绝。 – 2015-03-06 23:35:14