代码改变世界

从Atlas到Microsoft ASP.NET AJAX(7) - ScriptManager and ScriptManagerProxy Controls, Extender Controls

2006-10-22 12:18  Jeffrey Zhao  阅读(4358)  评论(12编辑  收藏  举报
ScriptManager and ScriptManagerProxy Controls

Script References

CTP版本中的ScriptManagerScriptManagerProxy控件提供了引用所需Client FX脚本的方式,同时也提供了一个使用pathname属性来指定脚本引用的方法。下面的示例展示了这些控件的使用方式。
<atlas:ScriptManager runat="server" ID="ScriptManager">
    
<Scripts>
        
<atlas:ScriptReference ScriptName="AtlasUIGlitz" />
        
<atlas:ScriptReference Path="~/Scripts/Custom.js" />
    
</Scripts>
</atlas:ScriptManager>

被CTP版本所限制的几个关键情形在RTM版本中得以解决。事实上,RTM版本向页面开发人员提供了许多可选设置。在RTM版本中所作的改变包括:
  • ScriptManager依旧保留了对于必须和可选脚本的支持。对于可选脚本来说,与CTP版本最大的区别在于现在没有了ScriptName枚举。这个功能被一个能够适合更多场合的模型所替代,该模型允许第三方使用基于程序集的方式来发送Web资源脚本。下面的示例展示了新的模型,并且使用了Value-Add包中额外的可选脚本。如下:
    <asp:ScriptManager runat="server" ID="ScriptManager">
        
    <Scripts>
            
    <asp:ScriptReference
                
    Name="Microsoft.Web.Resources.ScriptLibrary.PreviewScript.js" 
                Assembly
    ="Microsoft.Web.Preview" />
            
    <asp:ScriptReference
                
    Name="Microsoft.Web.Resources.ScriptLibrary.PreviewGlitz.js" 
                Assembly
    ="Microsoft.Web.Preview" />
            
    <asp:ScriptReference Path="~/Scripts/Custom.js" />
        
    </Scripts>
    </asp:ScriptManager>
  • ScriptManager控件允许您以引用静态文件的方式引用磁盘上的文件,并以此提高性能。这点同时应用于Client FX和自定义的脚本。这点依靠ScriptPath属性(全局路径)来实现。这个属性标明了一个根路径,控间会在此后加上程序集名和版本号作为脚本引用的路径。这意味着,如果您将组件升级为一个新的版本(例如,System.Web.Extensions),页面依然会正常运行,只是它会引用新的脚本文件。下面的例子展示了ScriptPath属性的使用方式:
    <asp:ScriptManager runat="server" ID="ScriptManager" ScriptPath=”~/Scripts”>
        
    <Scripts>
            
    <asp:ScriptReference 
                
    Name="Microsoft.Web.Resources.ScriptLibrary.PreviewScript.js" 
                Assembly
    ="Microsoft.Web.Preview" />
            
    <asp:ScriptReference 
                
    Name="Microsoft.Web.Resources.ScriptLibrary.PreviewGlitz.js" 
                Assembly
    ="Microsoft.Web.Preview" />
            
    <asp:ScriptReference Path="~/Scripts/Custom.js" />
        
    </Scripts>
    </asp:ScriptManager>
    由于使用了ScriptPath设置全局(根)路径,这个模型意味着那些脚本文件所在的位置是ScriptPath的值之后再加上程序集名和它的版本。在现在的示例中,它表示了:
    • 框架脚本为:~/Scripts/Microsoft.Web.Extensions/1.0.<build>.0/*.js。
    • 可选的Preview脚本为:~/Scripts/Microsoft.Web.Preview/1.0.0.0/*.js。
    您依旧能够在应用里使用Path属性来覆盖ScriptPath的值。您也能够通过将IgnoreScriptPath属性设为true来强行使用程序集内的脚本。
  • 您能够使用Path属性来引用磁盘上的脚本文件,您也可能直接指定某个特定的Client FX的脚本。如果您修改了Client FX脚本,您能够直接引用修改后的版本而不是框架中的脚本。下面的示例说明了这一点:
    <asp:ScriptManager runat="server" ID="ScriptManager">
        
    <Scripts>
            
    <asp:ScriptReference Name="MicrosoftAjax.js" 
                Path
    ="~/Scripts/MicrosoftAjax2.js" />
        
    </Scripts>
    </asp:ScriptManager>
  • ScriptManager控件允许您指定一个Web Resource脚本,以此提供IntelliSense功能,您可以使用ScriptRefernce标签上指定的名称和程序集来做到这一点。
  • ScriptManager提供了ResolveScripts事件,该事件会为每一个脚本而触发以此,包括客户端框架脚本。您能够响应ResolveScripts事件来动态地改变脚本的引用,将其指向另一个路径。例如,您能够将脚本路径指向离当前请求IP地理位置最近的服务器,以此来提升性能。下面的示例展示了操作ResolveScripts事件的方式:
    <asp:ScriptManager runat="server" ID="ScriptManager"
        OnResolveScriptReference="ResolveScripts">
        ...
    </asp:ScriptManager>

    <script runat="server">
        protected 
    void ResolveScripts(object sender, ScriptReferenceEventArgs e) {
            e.Script.Path 
    = “~/newLocation/” + e.Script.Name;
            ...
        }
    </script>

Handling Debug and Release Scripts

在CTP版本中,ScriptManager控件能够指定一个是使用Debug还是Release类型的脚本引用。像之前提到的那样,两者的区别仅仅是Release脚本删除了不必要的空格而已。在页面中输出哪种类型的脚本,是由Web.config中debug设置决定的。

根据我们得到的用户反馈,在RTM版本中使用了一个新的模型,它能够允许ScriptManager控件将服务器端和客户端的debug设置分开。ScriptManager控件为客户端使用Debug脚本的依据在于添加为引用的命名规则。您能够总是引用Release脚本,而ScriptManager控件会为您处理好别的事情,例如debug脚本不存在时的fallback控制。

在RTM版本中,Release和Debug脚本都会经过压缩模块。在Release脚本中,它还会被“crunched”(混淆的意思?)——Beta暂不支持。


Script and Other Resource Registration APIs

正如UpdatePanel的部分所解释过的,在RTM版本中ScriptManager控件提供了新的API可用于注册脚本和其余的资源,这使得ScriptManager和客户端pageRequestManager能够控制如何跟踪在UpdatePanel里出现的部分页面PostBack。

另外,在RTM版本中,包括使用了Client FX的Entender在内的新控件,都会在将它们自己注册给ScriptManager后,再将自己的脚本库和其他的客户端对象注册给ScriptManager



Extender Controls

Extender控件能够允许你为现有的服务器控间添加客户端Behavior,以此增加新的功能和行为。在CTP版本中,您使用了一个单独的Extender控件,并设置它的控件属性与目标服务器控件一一对应,就像下面示例所展示的一样:
<asp:TextBox runat="server" ID="City" />
<br/>
<asp:TextBox runat="server" ID="CountryOrRegion" />

<atlas:AutoCompleteExtender runat="server" ID="AutoComplete1">
    
<atlas:AutoCompleteProperties TargetControlID="City"
        Enabled
="True" ServicePath="AutoCompleteWebService.asmx" 
        ServiceMethod
="GetCompletionList" />
    
<atlas:AutoCompleteProperties TargetControlID="CountryOrRegion"
        Enabled
="True" ServicePath="AutoCompleteWebService.asmx" 
        ServiceMethod
="GetCompletionList" />
</atlas:AutoCompleteExtender>


Extender Controls and the Component Developer

在CTP版本中,组件开发人员能够使用ExtenderControl基类和ExtenderControlProperties类进行开发。在这里,开发人员负责开发相关Behavior的客户端脚本,然后使用Extender的RenderScript方法中的ScriptTextWriter类型参数将其XML-Script输出。组件开发人员会将他们的脚本注册给控件的特定生命周期事件,例如Init事件。

根据用户反馈,并考虑到减轻其复杂度能够有利于今后的扩展,我们实现了一个新的模型。在RTM版本中,组件开发人员直接使用了ExtenderControl类。开发人员能够为自己的控件实现IScriptControlIExtenderControl接口,以此来处理页面中存在ScriptManager的情况。

Extender控件依然会注册给ScriptManager控件。然而,它们会被框架要求提供它们的所需的脚本类库,并提供一个新的ScriptDescriptor类型的对象,从而避免了旧的模型中需要控件开发人员在控件的生命周期中自行输出这些信息。ScriptDescriptor类型会与ComponentBehaviorControl等客户端类型一一映射,这种做法为客户端对象抽象了脚本的生成过程,这使生成客户端对象变成了一件简单的事情。

注意:在RTM的Beta版本中,控件将在其在Init时注册给ScriptManager。这一点在RTM中会被改变为使用PreRender。这样的话,在Extender的一个TargetControl是不可见的情况下,在Beta版本中,这个Extender依旧会向其请求脚本引用和描述符。这一点在RTM中会被改变。

  在这种模型下,服务器控件就无需得知应该如何将脚本输出了,这方便了今后的扩展和支持。下面的示例简单展示了在RTM版本中ScriptDescriptor类型的使用方式:
protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors
    (Control targetControl) {
    ScriptBehaviorDescriptor descriptor 
=
        
new ScriptBehaviorDescriptor("Sample.UI.BorderBehavior", targetControl.ClientID);
            
    
if (!Color.IsEmpty) {
        descriptor.AddProperty(
"color", ColorTranslator.ToHtml(Color));
    }
    
if (Style != BorderStyle.NotSet) {
        descriptor.AddProperty(
"style", Style.ToString());
    }
    
if (!Width.IsEmpty) {
        descriptor.AddProperty(
"width", Width.ToString());
    }
    yield 
return descriptor;
}

protected override IEnumerable<ScriptReference> GetScriptReferences() {
    ScriptReference reference 
= new ScriptReference();
    Reference.Path 
= ResolveClientUrl("~/ScriptControls/BorderBehavior.js"));
    yield
return reference;
}

在这个示例中,我们使用了ScriptDescriptor类型中的AddProperty方法来设置客户端对象的属性值。请注意我们也使用了ScriptReference类型来返回一个特定的脚本引用,在这里我们使用了一个静态的URL,而不是Web Resource脚本引用。

Comment  上面的例子中有些小错误,我在参考了那些控件的代码后作了轻微的改动。