В статье предлагается единый набор правил для грамотной/поддерживаемой/расширяемой организации архитектуры web-контролов с использованием платформы FlexberryASP.NET.
Подключение скриптов и стилей
- Контрол должен быть максимально автономен с точки зрения зависимостей от скриптов/стилей. Должна быть возможность подключить контрол на пустой ASP.NET странице (System.Web.UI.Page) без дополнительных манипуляций.
- все используемые JS-библиотеки и скрипты должны подключаться самим контролом;
- если контрол использует общие JS-библиотеки (например, jQuery), то все зависимые скрипты должны подключать после этапа Init (Load и далее) т.к. базовые библиотеки подключаются в MasterPage.Init; подключение на этапе Init приведет к тому, что требуемая библиотека будет подключаться позже в разметке со всеми вытекающими последствиями;
- Все скрипты и стили должны храниться в веб-ресурсах сборки.
- Подключать все скипты и стили следует при помощи PageContentManager в
OnLoad
.- это предотвращает множественное подключение одних и тех же скриптов/стилей, если файл поддключается в нескольких местах (контролах);
Инициализация внутренней структуры контрола
Загрузка данных
- Все данные должны быть полностью загружены к концу этапа Load
Работа с идентификаторами
Особенности генерации клиентских идентификаторов контролов в ASP.NET:
- Начиная с .NET Framework 4, для генерации ClientId используются несколько алгоритмов - т.н. ClientIDMode (MSDN).
- Если у контрола не указан ID (ID == null), то он будет автоматически сгенерирован при первом обращении к ClientID используя текущий ClientIDMode.
- Если у контрола указан id в атрибутах, и указан ID, то при рендеринге будет использован CleintID. Если ID не указан, то будет использовано значение из атрибута.
В связи с этим может появляться странное поведение при генерации идентификаторов в отладичке, например, при использовании Watch
.
Пример:
_inputField = new HtmlGenericControl("div"); // ID не задан => _inputField.ID == null
_inputField.Attributes["id") = "SomeID"; // Клиентский идентификатор задан через HTML атрибут.
// Если где-то до рендеринга / в Watch будет вызван _inputField.ClinetID,
// то ID != null => будет использован сгенерированный CleintID.
Ожидаемый результат рендеринга:
<div id="SomeID"></div>
Полученный результат рендеринга (при обращении к ClientID
):
<div id="ctl90"></div>