Пользовательский элемент управления ASP.NET. Какой лучший способ включить встроенную ссылку CSS только один раз? - PullRequest
9 голосов
/ 07 октября 2010

Проблема: я встраиваю файл 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.

Ответы [ 3 ]

9 голосов
/ 07 октября 2010

Чтобы предотвратить дублирование при отправке файлов 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);
}

Сначала мы проверяем, был ли указанный сценарий ранее зарегистрирован. Если нет, мы добавим его.

3 голосов
/ 08 июля 2011

Я не знаю почему, но ваше решение не сработало для меня, вызов ClientScript.IsClientScriptBlockRegistered всегда возвращал false.Но предложение Джона Бледсо по ссылке, которую вы уже предоставили ( здесь ), сработало для меня:

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 голосов
/ 07 октября 2010

Почему бы просто не создать частную логическую переменную в элементе управления, который вы установили в true при первоначальном создании CSS.Затем вы можете проверить это при вызове метода, чтобы увидеть, был ли уже установлен 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...