ASP.NET自定义控件 - 仅包含一次嵌入式CSS引用的最佳方法是什么?

Nig*_*888 9 css asp.net dependencies custom-server-controls

问题:我将CSS文件嵌入到具有多个控件的自定义控件库中.我想为所有控件共享相同的CSS文件,无论它们在给定表单上有多少个实例.当表单上有多个控件时,我想在ASP.NET页面的HTML标题中引用一个CSS文件.

这是我提出的(到目前为止):

Public Sub IncludeStyles(ByVal Page As System.Web.UI.Page)
    'Don't include the reference if it already exists...
    If Page.Header.FindControl("MyID") Is Nothing Then
        Dim cssUrl As String = Page.ClientScript.GetWebResourceUrl(GetType(Common), StylePath)

        Dim css As New System.Web.UI.HtmlControls.HtmlGenericControl("link")
        With css
            .Attributes.Add("rel", "stylesheet")
            .Attributes.Add("type", "text/css")
            .Attributes.Add("href", cssUrl)
            .ID = "MyID"
        End With

        Page.Header.Controls.Add(css)
    End If
End Sub
Run Code Online (Sandbox Code Playgroud)

好吧,它的工作原理......但是这里明显的缺陷是FindControl()用来查看窗体上是否存在控件.虽然我使用的是命名容器,但它似乎仍在工作,但我确信有一些方法可以解决这个问题.在具有相同ID的表单上添加另一个控件肯定是一个......

问题:什么是确保标题控件只添加到HTML标题一次的更好方法?

注意:该ClientScript.RegisterClientScriptResource()方法有一个接受.NET类型的参数,此类型可用于确保代码每页只输出一次.不幸的是,此方法仅适用于JavaScript文件引用.如果有CSS引用的内置等价物,那将是我的偏好.

更新:

我发现了一个稍微更优雅的方式来做到这一点在这里通过Page.ClientScript.RegisterClientScriptBlock并告诉它要包括自己的脚本标签,但是瑞克指出,这并不脚本添加到HTML头标记,也不符合xhtml.

更新2:

我在这个线程上看到了另一个有趣的想法,但循环遍历控件集合并不是一个非常好的解决方案,如果在页面上有多个引用和几个控件,则会增加很多开销.

Chris Lively想出了一个更好的解决方案,需要更少的代码.这是我用新解决方案改变的功能:

Public Sub IncludeStyles(ByVal Page As System.Web.UI.Page)
    If Not Page.ClientScript.IsClientScriptBlockRegistered(StyleName) Then
        Dim cssUrl As String = Page.ClientScript.GetWebResourceUrl(GetType(Common), StylePath)

        Dim css As New System.Web.UI.HtmlControls.HtmlGenericControl("link")
        With css
            .Attributes.Add("href", cssUrl)
            .Attributes.Add("rel", "stylesheet")
            .Attributes.Add("type", "text/css")
        End With

        Page.Header.Controls.Add(css)
        Page.ClientScript.RegisterClientScriptBlock(GetType(Page), StyleName, "")
    End If
End Sub
Run Code Online (Sandbox Code Playgroud)

有关此解决方案的几点注意事项.在他的原始帖子中,Chris使用的IsClientScriptIncludeRegistered()方法不是该方法的相应RegisterClientScriptBlock()方法.要正确使用此功能,必须完成测试IsClientScriptBlockRegistered().

另外,请注意传递给的类型RegisterClientScriptBlock().我将一个自定义数据类型传递给了这个方法(在我的所有控件中都是相同的),但它没有以这样的方式注册,即IsClientScriptBlockRegistered()测试可以工作.为了使其起作用,必须将当前Page对象作为Type参数传入.

虽然不可否认这个解决方案感觉有点像黑客,但它a)不需要大量的代码或开销,b)在页面上产生完全所需的输出,并且c)是符合xhtml的代码.

Not*_*tMe 9

为了防止从服务器控件发出css文件时出现重复,我们执行以下操作:

if (!Page.ClientScript.IsClientScriptBlockRegistered("SoPro." + id)) {
    HtmlLink cssLink = new HtmlLink();
    cssLink.Href = cssLink.Href = Page.ClientScript.GetWebResourceUrl(this.GetType(), styleSheet);
    cssLink.Attributes.Add("rel", "stylesheet");
    cssLink.Attributes.Add("type", "text/css");
    this.Page.Header.Controls.Add(cssLink);
    this.Page.ClientScript.RegisterClientScriptBlock(typeof(System.Web.UI.Page), "SoPro." + id, String.Empty);
}
Run Code Online (Sandbox Code Playgroud)

首先,我们测试以查看命名脚本是否先前已注册.如果没有,我们将其添加进去.