2010-10-06 22 views
10

問題:我正在用一些控件將CSS文件嵌入到自定義控件庫中。我想爲所有控件共享相同的CSS文件,而不管它們在給定表單上有多少個實例。當表單上有多個控件時,我想要在ASP.NET頁面的HTML標頭中正好引用一個CSS文件。ASP.NET自定義控件 - 只包含一次嵌入式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 

好,它的工作原理......但這裏的明顯缺陷是使用FindControl(),看看錶格上存在控制。雖然我使用命名容器,但它似乎仍在工作,但我確信有一些方法可以打破這一點。在具有相同ID的窗體上添加另一個控件肯定是一個...

問題:什麼是更好的方法來確保只能將標題控件添加到HTML標頭一次?

注意:ClientScript.RegisterClientScriptResource()方法有一個接受.NET類型的參數,這種類型可以用來確保代碼每頁僅輸出一次。不幸的是,這種方法只適用於JavaScript文件引用。如果有一個CSS引用的內置等價物,那將是我的首選。

更新:

我發現了一個稍微更優雅的方式使用Page.ClientScript.RegisterClientScriptBlock並告訴它要包括自己的腳本標籤來做到這一點here,但是瑞克指出,這並未」將腳本添加到html頭標記中,並且不符合xhtml標準。

更新2:

我看到this thread另一個有趣的想法,而是通過控制集合循環並不是一個很好的解決方案,並增加了大量的開銷,如果你有幾個引用和幾個控件的頁面上。

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 

有幾件事情要注意有關此解決方案。 Chris在他的原始文章中使用了IsClientScriptIncludeRegistered()方法,該方法不是RegisterClientScriptBlock()方法的相應方法。要正確地完成此功能,測試必須使用IsClientScriptBlockRegistered()完成。

另外,請注意傳遞到RegisterClientScriptBlock()的類型。我將一個自定義數據類型傳遞給了這個方法(在我的所有控件中都是一樣的),但是它沒有以IsClientScriptBlockRegistered()測試可以工作的方式進行註冊。爲了使其起作用,必須將當前的Page對象作爲Type參數傳入。

儘管承認這個解決方案有點像黑客,它a)不需要太多的代碼或開銷,b)在頁面上產生所需的輸出,以及c)是符合xhtml的代碼。

+0

概念,爲什麼CSS不是該網站的主css文件的一部分,即獲取和客戶端緩存? – jball 2010-10-06 20:35:13

+2

這是一個控制庫,理論上可以在任何網站中使用,我更喜歡使用單獨的CSS(可以很容易地被覆蓋),而不是硬編碼所有的CSS內聯(像微軟在許多情況下那樣)。換句話說,我的控件應該完全不知道它們託管的網站。 – NightOwl888 2010-10-06 21:27:17

+0

w3validator不喜歡GetWebResourceUrl返回的未編碼的&符號。要解決這個問題,請使用Page.Server.HtmlEncode(url) – daniatic 2013-10-30 10:03:44

回答

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); 
} 

首先我們測試,看看是否已命名的腳本先前已註冊。如果沒有,我們將其添加進去。

+0

有趣的想法,起初我認爲它會工作。但是,我嘗試過,並且有幾個問題(除非我錯過了某些東西)。這在mime類型「text/javascript」下注冊CSS。另外,它會創建一個「腳本」標籤,而不是「鏈接」標籤。第三,雖然沒有那麼重要,但標籤並未包含在文檔的頭部。 – NightOwl888 2010-10-06 21:39:46

+0

糟糕。錯誤的摘要。再看一遍。 – NotMe 2010-10-06 22:08:08

+0

好主意!我在原始文章中添加了一個更正版本。測試必須使用RegisterClientScriptBlockInclude完成,但除此之外,此代碼工作良好。 – NightOwl888 2010-10-07 09:29:00

0

爲什麼不在剛創建CSS時設置爲true的控件中創建一個私有布爾變量?然後你可以檢查這個方法被調用時,看看是否已經設置了CSS。下面的示例(我的VB是生鏽所以可能會略低錯)

Private _hasCss As Boolean = False 

Public Sub IncludeStyles(ByVal Page As System.Web.UI.Page) 
    'Don't include the reference if it already exists... 
    If Not _hasCss 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) 
     _hasCss = True 

    End If 
End Sub 
+0

編碼url不會工作。首先,您將變量設置爲private - 意味着每個控件實例都有一個單獨的副本。共享變量可能會在不同的用戶之間出現問題,所以這也不起作用。 – NightOwl888 2010-10-06 21:20:04

+0

你是對的NightOwl,我完全錯過了! – WDuffy 2010-10-07 10:24:29

3

我不知道爲什麼,但是您的解決方案對我來說不起作用,ClientScript.IsClientScriptBlockRegistered調用總是返回false。但約翰·布萊索的你已經提供的鏈接(here)在建議的工作對我來說:

public static void IncludeStylesheet(Page page, string href, string styleID) 
{ 
    //Prevent the stylesheet being included more than once 
    styleID = "_" + styleID; 
    if (HttpContext.Current.Items[styleID] == null) 
    { 
     HtmlLink htmlLink = new HtmlLink(); 
     htmlLink.Href = href; 
     htmlLink.Attributes.Add("rel", "stylesheet"); 
     htmlLink.Attributes.Add("type", "text/css"); 
     page.Header.Controls.Add(htmlLink); 
     HttpContext.Current.Items[styleID] = true; 
    } 
} 
+0

這也是一個有趣的想法,不知道爲什麼我沒有考慮過使用HttpContext.Items,但感謝分享。 – NightOwl888 2013-02-22 14:47:16

相關問題