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