Benutzerdefiniertes ASP.NET-Steuerelement - Wie kann eine eingebettete CSS-Referenz nur einmal eingefügt werden?

Das Problem: Ich binde eine CSS-Datei in eine benutzerdefinierte Steuerelementbibliothek mit mehreren Steuerelementen ein. Ich möchte dieselbe CSS-Datei für alle Steuerelemente freigeben, unabhängig davon, wie viele Instanzen in einem bestimmten Formular vorhanden sind. Wenn sich mehr als ein Steuerelement im Formular befindet, möchte ich genau 1 Verweis auf die CSS-Datei im HTML-Header 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 vonFindControl(), um zu sehen, ob das Steuerelement im Formular vorhanden ist. Obwohl ich Namenscontainer verwende und es immer noch zu funktionieren scheint, bin ich sicher, dass es eine Möglichkeit gibt, dies zu brechen. Das Hinzufügen eines weiteren Steuerelements auf dem Formular mit derselben ID ist mit Sicherheit eines ...

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

Beachten Sie dasClientScript.RegisterClientScriptResource()ie @ -Methode verfügt über einen Parameter, der einen .NET-Typ akzeptiert. Mit diesem Typ kann sichergestellt werden, 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.

Aktualisieren

Ich habe einen etwas eleganteren Weg gefunden, dies zu tunHie Indem Sie Page.ClientScript.RegisterClientScriptBlock verwenden und sagen, dass Sie Ihre eigenen Skript-Tags einschließen, wird das Skript jedoch nicht zum HTML-Head-Tag hinzugefügt und ist auch nicht xhtml-kompatibel.

Update 2:

Ich sah eine andere interessante Idee aufdieser Thread, aber das Durchlaufen der Controls-Auflistung ist keine sehr gute Lösung und erhöht den Aufwand erheblich, wenn Sie mehrere Verweise und Steuerelemente auf der Seite haben.

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

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

Ein paar Dinge, die Sie zu dieser Lösung beachten sollten. In seinem ursprünglichen Beitrag verwendete Chris dasIsClientScriptIncludeRegistered() -Methode, die nicht der @ -Methode entspraRegisterClientScriptBlock() Methode. Um diese Funktion korrekt auszuführen, muss der Test mit @ durchgeführt werdeIsClientScriptBlockRegistered().

chten Sie auch sorgfältig auf den Typ, der an @ übergeben wirRegisterClientScriptBlock(). Ich habe dieser Methode einen benutzerdefinierten Datentyp übergeben (der für alle meine Steuerelemente gleich ist), der jedoch nicht so registriert wurde, dass dasIsClientScriptBlockRegistered()test würde funktionieren. Damit es funktioniert, muss das aktuelle Page-Objekt als Type-Argument übergeben werden.

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

Antworten auf die Frage(6)

Ihre Antwort auf die Frage