Проблема: я встраиваю файл CSS в библиотеку пользовательских элементов управления с несколькими элементами управления. Я хочу использовать один и тот же файл CSS для всех элементов управления, независимо от того, сколько их экземпляров находится в заданной форме. Когда в форме находится более одного элемента управления, я бы хотел, чтобы в заголовке HTML страницы ASP.NET была ровно 1 ссылка на файл 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()
, чтобы увидеть, существует ли элемент управления в форме. Несмотря на то, что я использую именование контейнеров, и оно все еще работает, я уверен, что есть какой-то способ это сломать. Добавление другого элемента управления в форму с таким же идентификатором, безусловно, один ...
Вопрос: Как лучше всего обеспечить, чтобы элемент управления заголовком добавлялся в заголовок HTML только один раз?
Примечание. У метода ClientScript.RegisterClientScriptResource()
есть параметр, принимающий тип .NET, и этот тип можно использовать для обеспечения вывода кода только один раз на страницу. К сожалению, этот метод работает только со ссылками на файлы JavaScript. Если для ссылок CSS есть встроенный эквивалент, я бы предпочел.
Обновление:
Я обнаружил немного более элегантный способ сделать это здесь , используя Page.ClientScript.RegisterClientScriptBlock и сказав, что вы включаете свои собственные теги сценария, однако, как указывает Рик, это не добавляет сценарий для тега html head и также не совместим с xhtml.
Обновление 2:
Я увидел еще одну интересную идею в этой ветке , но циклический просмотр коллекции элементов управления не очень хорошее решение и добавляет много накладных расходов, если у вас есть несколько ссылок и несколько элементов управления на странице.
Крис Лайвли придумал лучшее решение, которое требует меньше кода. Вот моя функция, измененная новым решением:
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
Несколько замечаний по поводу этого решения. В своем первоначальном посте Крис использовал метод IsClientScriptIncludeRegistered()
, который не соответствовал методу RegisterClientScriptBlock()
. Чтобы сделать эту функцию правильно, тест должен быть выполнен с IsClientScriptBlockRegistered()
.
Кроме того, обратите особое внимание на тип, который передается в RegisterClientScriptBlock()
. Я передал пользовательский тип данных этому методу (одинаковый для всех моих элементов управления), но он не регистрировался таким образом, чтобы тест IsClientScriptBlockRegistered()
работал. Для того, чтобы он функционировал, текущий объект Page должен быть передан как аргумент Type.
Хотя по общему признанию это решение выглядит как хакерство, оно а) не требует большого количества кода или служебных данных, б) выдает именно желаемый результат на странице и в) является кодом, совместимым с xhtml.