9 Stimmen

ASP.NET Custom Control - Was ist der beste Weg, um eingebettete CSS-Referenz nur einmal enthalten?

Das Problem: Ich bette eine CSS-Datei in eine benutzerdefinierte Steuerelementbibliothek mit mehreren Steuerelementen ein. Ich möchte dieselbe CSS-Datei für alle Steuerelemente verwenden, unabhängig davon, wie viele Instanzen von ihnen sich in einem bestimmten Formular befinden. Wenn mehr als ein Steuerelement auf dem Formular ist, möchte ich genau 1 Verweis auf die CSS-Datei in der HTML-Kopfzeile der ASP.NET-Seite.

Hier ist, was ich mir (bisher) ausgedacht habe:

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

Ok, es funktioniert... aber der offensichtliche Fehler hier ist die Verwendung von FindControl() um festzustellen, ob das Steuerelement auf dem Formular vorhanden ist. Obwohl ich Benennungscontainer verwende und es immer noch zu funktionieren scheint, bin ich sicher, dass es einen Weg gibt, dies zu umgehen. Hinzufügen eines anderen Steuerelements auf dem Formular mit der gleichen ID ist sicherlich eine...

Die Frage: Wie kann man besser sicherstellen, dass das Header-Steuerelement nur genau einmal zum HTML-Header hinzugefügt wird?

Anmerkung: Die ClientScript.RegisterClientScriptResource() Methode hat einen Parameter, der einen .NET-Typ akzeptiert, und dieser Typ kann verwendet werden, um sicherzustellen, dass der Code nur einmal pro Seite ausgegeben wird. Leider funktioniert diese Methode nur mit JavaScript-Dateiverweisen. Wenn es ein eingebautes Äquivalent für CSS-Referenzen gibt, wäre das meine Präferenz.

Aktualisierung:

Ich habe einen etwas eleganteren Weg gefunden, dies zu tun ici indem Sie Page.ClientScript.RegisterClientScriptBlock verwenden und ihm mitteilen, dass Sie Ihre eigenen Skript-Tags einfügen. Wie Rick jedoch feststellt, fügt dies das Skript nicht zum HTML-Head-Tag hinzu und ist auch nicht xhtml-konform.

Update 2:

Eine weitere interessante Idee habe ich auf dieses Thema Die Schleifenbildung durch die Steuerelementsammlung ist jedoch keine sehr gute Lösung und führt zu einem großen Overhead, wenn Sie mehrere Verweise und mehrere Steuerelemente auf der Seite haben.

Chris Lively hat eine bessere Lösung gefunden, die weniger Code erfordert. Hier ist meine Funktion, die mit der neuen Lösung geändert wurde:

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

Zu dieser Lösung gibt es ein paar Dinge zu beachten. In seinem ursprünglichen Beitrag verwendete Chris die IsClientScriptIncludeRegistered() Methode, die nicht die entsprechende Methode der RegisterClientScriptBlock() Methode. Damit dies korrekt funktioniert, muss der Test mit IsClientScriptBlockRegistered() .

Achten Sie außerdem sorgfältig auf den Typ, der an RegisterClientScriptBlock() . Ich habe einen benutzerdefinierten Datentyp an diese Methode übergeben (der gleiche für alle meine Steuerelemente), aber er wurde nicht so registriert, dass die IsClientScriptBlockRegistered() Test funktionieren würde. Damit er funktioniert, muss das aktuelle Seitenobjekt als Argument Type übergeben werden.

Obwohl sich diese Lösung zugegebenermaßen ein wenig wie ein Hack anfühlt, erfordert sie a) nicht viel Code oder Overhead, b) erzeugt sie genau die gewünschte Ausgabe auf der Seite und c) ist der Code xhtml-konform.

9voto

NotMe Punkte 86089

Um eine Duplizierung bei der Ausgabe von CSS-Dateien von Server-Steuerelementen zu verhindern, gehen wir wie folgt vor:

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

Zunächst wird geprüft, ob das genannte Skript bereits registriert wurde. Wenn nicht, fügen wir es hinzu.

3voto

Colin Punkte 21707

Ich weiß nicht, warum, aber Ihre Lösung hat bei mir nicht funktioniert, der Aufruf ClientScript.IsClientScriptBlockRegistered gab immer false zurück. Aber der Vorschlag von John Bledsoe auf dem Link, den Sie bereits angegeben haben ( ici ) hat bei mir funktioniert:

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

0voto

William Punkte 7758

Warum erstellen Sie nicht einfach eine private boolesche Variable im Steuerelement, die Sie bei der ersten Erstellung des CSS auf true setzen? Sie können dann beim Aufruf der Methode prüfen, ob das CSS bereits gesetzt wurde. Beispiel unten (mein VB ist eingerostet, könnte also leicht falsch sein)

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X