Разработка электроники,

Систем автоматики,

Программного обеспечения

8(981)186-50-82

ООО "Антех ПСБ",
Санкт-Петербург

anteh@bk.ru

antehru@gmail.com

©

Добавление/использование встроенных ресурсов web серверного элемента управления gif jpg png ico, css, js. C# ASP.NET VS2008 System.Web.UI.WebResource

Сайт https://anteh.ru

Создаем свой серверный web элемент управления, наследуемый например от GridView или другого штатного контрола public class EGridView : GridView, IScriptControl. И для расширения функциональности нужно использовать дополнительные файлы .gif, .jpg, .png, .ico, .css, .js, .html и т.д. Т.е. эти файлы будут встроенны в .dll контрола.

Добавление графического изображения во встроенные ресурсы сборки

Рассмотрим добавление и использование изображения, например .jpg формата как фонового изображение текущего контрола 4шага.

1. Размещаем файл изображения в проекте серверного элемента управления(контрола). Файл помещаем в корень проекта, либо в какую -либо папку проекта.

2. В свойствах файла изображения нужно задать "Действие при построении" как встроенный ресурс(Embedded Resource).

3. Нижеприведённую строку-атрибут […] добавляем в .cs файл проекта серверного элемента управления перед namespace…. Или в файл AssemblyInfo.cs разрабатываемого серверного элемента управления.

…
[assembly: System.Web.UI.WebResource("ServControlEGridView.eresource.pictures.background.jpg", "image/jpg")]//, PerformSubstitution = true)]
…
namespace ServControlEGridView
{…}

Здесь ServControlEGridView.eresource.pictures.background.jpg -путь к web ресурсу. ServControlEGridView -пространство имён контрола, eresource -папка находящаяся в корне проекта контрола, pictures -папка вложенная в eresource, background.jpg -собственно файл изображения. Вместо '/', при указании пути, используется точка. "image/jpg" -тип ресурса. Ниже скриншот того, как это выглядит в студии:1

И наконец PerformSubstitution -если вкратце, то =true, если описываемый ресурс имеет ссылки на другие ресурсы. Например для файлов изображений не нужен, по умолчанию =false. Для .css .html .js указывется =true, если в файлах .css .html .js имеются ссылки на какие либо ресурсы. Если ссылок нет, то при PerformSubstitution =true хуже не было.

Если посмотреть на вопрос шире, то: в MSDN(перевод), написано: "если true, то внедренные ресурсы разрешаются во время обработки ресурсов; в противном случае - значение false. Значение по умолчанию false. Когда ресурс передается из сборки в ответ, ссылка на другие веб-ресурсы во внедренных ресурсах может быть разрешена в это время, если значение свойства PerformSubstitution=true." В общем трудно понять о чём речь. Нашось следующее объяснение: если PerformSubstitution=true, то Обработчик WebResource.axd будет выполнять автоматическую подстановку. Это позволит вам создать встроенный ресурс, указывающий на другие встроенные ресурсы. Например, рассмотрим веб-элемент управления, использующий несколько HTML файлов для предоставления вспомогательной информации. Вы можете применять гиперссылки для подключения одного HTML файла к другому, но при этом встраивать их в виде веб-ресурсов. Без автоматической подстановки вы не сможете создать ресурс, указывающий на другой ресурс, потому что не знаете имен ресурсов, которые сгенерирует ASP.NET. Но с автоматической подстановкой можно использовать оригинальное имя файла. Компилятор заменит вашу ссылку на имя файла правильным, автоматически сгенерированным именем ресурса. В общем для графического изображения параметр PerformSubstitution указывать не нужно, он по умолчанию итак =false.

4. Теперь в коде контрола осталось получить URL встроенного ресурса изображения. Обработчик WebResource.axd принимает запросы URL, извлекает запрашиваемый ресурс из соответствующей сборки и возвращает его содержимое. Т.е. не нужно возиться с картинками и сценариями, потому что файл WebResource.axd сделает всё самостоятельно, прямо из сборки вашего элемента управления.

Следующий код берёт url изображения 2 из текущей сборки контрола и задаёт в качестве фонового для строки заголовка текущего контрола:

protected override void OnInit(EventArgs e)
{
    //фоновая картинка текущего контрола
    this.BackImageUrl = Page.ClientScript.GetWebResourceUrl(typeof(ServControlEGridView.EGridView), "ServControlEGridView.eresource.pictures.background.jpg");
base.OnInit(e);
}

Здесь ServControlEGridView -пространство имён контрола, EGridView имя класса контрола. Задать фон контролу можно также из .css. Ниже рассмотрен подобный случай. В общем с другими графическими изображениями можно поступать похожим образом. Вместо typeof(ServControlEGridView.EGridView) можно использовать this.GetType()

Добавление *.css во встроенные ресурсы сборкиРассмотрим добавление и использование .css файла как встроенного ресурса серверного элемента управления.
Первые 2шага такие же как и при добавлении файла изображения в ресурсы. Шаг 3. отличается наличием параметра PerformSubstitution = true -предположим, что в файле .css будут ссылки на какие-либо дополнительные ресурсы текущего контрола, например графические изображения. Добавляем строку-атрибут:
[assembly: System.Web.UI.WebResource("ServControlEGridView.eresource.css.egv.css", "text/css", PerformSubstitution = true)]
В файле .css ссылка на графическое изображение в этой же сборке может выглядеть следующим образом(селектор класса .bckgr):

/*.css file*/
Body /*type selector*/
{       }
.bckgr /*class selector*/
{
        background-image: url('<%=WebResource("ServControlEGridView.eresource.pictures.background.jpg")%>'); 
}
.gv_headerrow
{
        color:#006666;
        text-decoration:underline;
        -moz-user-select:none;          /*зпрет выделения текста мышью для браузерного движка mozilla*/
        -webkit-user-select:none;       /*зпрет выделения текста мышью для браузерного движка webkit*/
        user-select:none;                       /*зпрет выделения текста мышью -не рабочая строка на всякий*/
        background-image: url('<%=WebResource("ServControlEGridView.eresource.pictures.background.jpg")%>');
}

Правило bckgr будет применено к ЛЮБОМУ элементу, атрибут CssClass которого равен 'bckgr' селектору.
4. Теперь программно в заголовок страницы добавляем ссылку на .css файл из текущей сборки. В разрабатываемый контрол добавляем следующие строки:

protected override void OnPreRender(EventArgs e)
{
   …
    if (!this.Page.ClientScript.IsClientScriptBlockRegistered("cssFile37"))
    {
        //в заголовок страницы добавляем ссылку на .css файл
        HtmlLink cssLink = new HtmlLink();
        cssLink.Href = this.Page.ClientScript.GetWebResourceUrl(this.GetType(),
                            "ServControlEGridView.eresource.css.egv.css");
        cssLink.Attributes.Add("rel", "stylesheet");
        cssLink.Attributes.Add("type", "text/css");
        this.Page.Header.Controls.Add(cssLink);
        //Устанавливаем флаг, что .css зарегистрирован. cssFile37 -произвольно придуманное строковое значение
        this.Page.ClientScript.RegisterClientScriptBlock(typeof(Page), "cssFile37", string.Empty, false);
    }            
    base.OnPreRender(e);
}
    
Здесь RegisterClientScriptBlock устанавливает флаг, сигнализирующий, что в заголовок страницы добавленна ссылка на .css файл. IsClientScriptBlockRegistered проверяет был ли установлен флаг. И если был, то в заголовке страницы не создаётся дублирующая ссылка на файл .css включённый в текущую сборку как встроенный ресурс. Это будет заметно, когда на одной странице будет находиться несколько подобных контроллов. "cssFile37" строковое значение, придумываемое произвольно.

После всех этих действий можно использовать название селектора класса из .css файла, как строковый параметр для присвоения стиля тому или иному элементу текущего контрола. Например:

this.HeaderRow.CssClass = "gv_headerrow"; //Задаём стиль заголовка GridView, а точнее каждой ячейке заголовка

здесь this -текущий контрол -унаследован от GridView. gv_headerrow -селектор класса из .css файла, при помощи которого задаём стиль строки заголовка GridView.

Заголовок GridView принимает следующий вид:123

По рисунку видно, что через this.HeaderRow.CssClass фон устанавливается не самому заголовку, а индивидуально каждой ячейке заголовка.

Добавление и использование .html файла в виде встроенного ресурса не производилось. Возможно там есть свои нюансы.

Добавление *.js во встроенные ресурсы сборки

Добавление, использование .js файлов, в качестве встроенных ресурсов, выглядит немного по другому. Первые три шага такие же, как и при добавлении .css файла.
4. Шаг -регистрация скрипта. На всякий случай, и для будующих применений регистрацию скриптов делаем через интерфейс IScriptControl, объявление класса контрола может выглядеть следующим образом: public class EGridView : GridView, IScriptControl
Нужно реализовать 2 функции интерфейса и добавить некоторый код в OnPreRender и Render, а также реализовать клиентский класс в .js файле.
Все таблицы стилей должны подключаться перед скриптами. Это позволит корректно объявить все свойства элементов перед выполнением кода jQuery, да и javascript в целом. Если этого не сделать, то возможна некорректная работа в некоторых браузерах, например тех, которые основаны на WebKit движке. Подобное реализовано в OnPreRender, код ниже.
Может пригодиться, при подключении, ни в какую не хотела работать jQuery библиотека. На участок javascript кода:

$(document).ready(function() 
{
    alert('HipManager ready');
    InitControl();
    // initialize you code
});

Firefox никак не реагировал, а в IE вываливалось сообщениe: "Ошибка выполнения Microsoft JScript: Объект не поддерживает свойство или метод "ready"" Причём на знак $ ругани не было. Ругань на $ была только когда jQuery совсем не был подключен.1234

При поиске проблемы встречалось упоминание, что mootool может конфликтовать с jQuery и нужно переходить с $ на jQuery. Но это к слову. В общем оказалось, что библиотеку jQuery в GetScriptReferences() функции интерфейса IScriptControl нужно объявлять выше/раньше остальных файлов скриптов, где возможно её применение. В общем картина в .cs файле создаваемого контрола должна быть такая:

protected virtual IEnumerable<ScriptReference> GetScriptReferences()
{    
    return new ScriptReference[] {  
        new ScriptReference("ServControlEGridView.eresource.js.jquery183min.js", this.GetType().Assembly.FullName),
        new ScriptReference("ServControlEGridView.EGridViewJ.js", this.GetType().Assembly.FullName), 
        new ScriptReference("ServControlEGridView.eresource.js.diff.js", this.GetType().Assembly.FullName)
                                 };
}

jquery183min.js -переименованная jQuery библиотека должна идти первым(нулевым) элементом массива.

Код 4го шага, который относится к регистрации javascript файлов через реализацию интерфейса IScriptControl:

namespace ServControlEGridView
{
    public class EGridView : GridView, IScriptControl
    {…}
…}

//Методы GetScriptDescriptors и GetScriptReferences вернут элементу управления 
//ScriptManager всю информацию, нужную ему для логического представления кода 
//созданного вами элемента управления как объекта сервера и клиента
private ScriptManager sm = null;
protected virtual IEnumerable<ScriptDescriptor> GetScriptDescriptors()
{
    ScriptControlDescriptor descriptor = new ScriptControlDescriptor("ServControlEGridView.EGridView", this.ClientID);
    //descriptor.AddProperty("normalImageUrl", this.ResolveClientUrl(this.ImageUrl));
    //descriptor.AddProperty("hoverImageUrl", this.ResolveClientUrl(this.HoverImageUrl));
    return new ScriptDescriptor[] { descriptor };
}

protected virtual IEnumerable<ScriptReference> GetScriptReferences()
{
    return new ScriptReference[] {  
        new ScriptReference("ServControlEGridView.eresource.js.jquery183min.js", this.GetType().Assembly.FullName), //jQuery библиотека, если используется, должна идти первоым элементом массива
        new ScriptReference("ServControlEGridView.EGridViewJ.js", this.GetType().Assembly.FullName), 
        new ScriptReference("ServControlEGridView.eresource.js.diff.js", this.GetType().Assembly.FullName)
                                 };
}

IEnumerable<ScriptReference> IScriptControl.GetScriptReferences() { return GetScriptReferences(); }
IEnumerable<ScriptDescriptor> IScriptControl.GetScriptDescriptors() { return GetScriptDescriptors(); }

protected override void OnPreRender(EventArgs e)
{
    //CSS СТИЛИ ДОЛЖНЫ ПОДКЛЮЧАТЬСЯ РАНЬШЕ СКРИПТОВ ИХ ИСПОЛЬЗУЮЩИХ иначе могут возникнуть нюансы минимум с браузерами на WebKit движке Safari и т.п.
    if (!this.Page.ClientScript.IsClientScriptBlockRegistered("JsCssReg67")) //Чтобы несколько раз, на одной странице, одно и тоже не регистрировать
    {
        //в заголовок страницы добавляем ссылку на .css файл
        HtmlLink cssLink = new HtmlLink();
        cssLink.Href = this.Page.ClientScript.GetWebResourceUrl(this.GetType(), "ServControlEGridView.eresource.css.egv.css");
        cssLink.Attributes.Add("rel", "stylesheet");
        cssLink.Attributes.Add("type", "text/css");
        this.Page.Header.Controls.Add(cssLink);
        //Регистрация .js скриптов
        if (!this.DesignMode) // Test for ScriptManager and register if it exists
        {
            sm = ScriptManager.GetCurrent(Page); //получаем ссылку на ScriptManager, размещённый на странице
            if (sm == null) throw new HttpException("Контрол ScriptManager должен присутствовать на текущей странице/r/nThere must be a script manager on the page");
            sm.RegisterScriptControl(this);
        }
        //Устанавливаем флаг, что .js .css зарегистрированы. JsCssReg67 -произвольно придуманное строковое значение
        this.Page.ClientScript.RegisterClientScriptBlock(typeof(Page), "JsCssReg67", string.Empty, false);
    }
    base.OnPreRender(e);
}

protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
    if (!this.Page.ClientScript.IsClientScriptBlockRegistered("Regreg98")) //Чтобы несколько раз, на одной странице, одно и тоже не регистрировать
    {
        if (!this.DesignMode) sm.RegisterScriptDescriptors(this); //регистрация дескрипторов сценария, созданных методом GetScriptDescriptors
        this.Page.ClientScript.RegisterClientScriptBlock(typeof(Page), "Regreg98", string.Empty, false); //Устанавливаем флаг. "Regreg98" произвольно выдуманный ключ
    }    
    …
    base.Render(writer);
}

5. Описание клиентского класса: ServControlEGridView.EGridViewJ.js файл .js:

/// <reference name="MicrosoftAjax.js"/>
Type.registerNamespace("ServControlEGridView"); //Объявляем пространство имен
ServControlEGridView.EGridView = function(element) //Конструктор клиентского класса для элемента управления. element -передаваемый DOM. EGridView -название класса контрола
{
    ServControlEGridView.EGridView.initializeBase(this, [element]); //Инициализация базового класса. Метод initializeBase вызывается до выполнения остального кода конструктора
}
ServControlEGridView.EGridView.prototype = //Прототип клиентского класса для элемента управления
{
initialize: function() //Если пользовательский элемент управления должен инициализировать свойства или прослушиватели событий, переопределите метод initialize в прототипе компонента
{
    ServControlEGridView.EGridView.callBaseMethod(this, 'initialize');
    // Добавьте здесь пользовательскую инициализацию
},
dispose: function() //Если пользовательский элемент управления должен освобождать ресурсы до своего удаления, переопределите метод dispose и освободите ресурсы в переопределенном методе. Это гарантирует немедленное освобождение ресурсов до удаления элемента управления. Освобождаемые ресурсы включают обработчики, используемые для привязки к событиям DOM. Убедитесь, что объект можно удалить, проверив, что удалены все возможные циклические ссылки между элементами DOM и объектом компонента
{
    //Добавьте здесь настраиваемые действия удаления
    ServControlEGridView.EGridView.callBaseMethod(this, 'dispose');
}
//
// Control properties
//
}
// Optional descriptor for JSON serialization
ServControlEGridView.EGridView.descriptor =
{
    properties: [{ name: 'draggColumnExt', type: String}]
}
ServControlEGridView.EGridView.registerClass('ServControlEGridView.EGridView', Sys.UI.Control); //Регистрация класса
if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded(); //Данный вызов необходим для того, чтобы Microsoft AJAX (библиотека) получила уведомление о загрузке файла JavaScript

В подтверждение успешного подключения jQuery после загрузки страницы можем наблюдать:45

Это сообщение формируемое кодом размещённым в diff.js:

$(document).ready(function() 
{
    alert('HipManager ready');    
});

В общем теперь можно использовать .js скрипты. И в частности jQuery.

TestICBEH_ER (VS2008 framework 3.5) -проект содержит пример реализации контрола с использованием .js файлов как встроенных ресурсов ASP.NET Server Control проекта.
Один из вариантов создания серверного контрола управления: создаём проект ASP.NET Server Control, класс контрола наследуем от расширяемого штатного элемента, например от GridView, добавляем и реализуем интерфейс IScriptControl. Создаём второй проект ASP.NET AJAX Server Control из него берём .js файл клиентского класса, как пример реализации, и помещаем его в ASP.NET Server Control проект, меняя всё что потребуется.

Copyright ©Новиков Алексей Александрович,

2012-2017 Санкт-Петербург, 197372, ООО "Антех ПСБ",

anteh собака bk.ru