Приветствуем вас, коллеги! Сегодня мы разберем одну очень интересную, на первый взгляд «мистическую» особенность работы платформы «1С:Предприятие 8.3» с управляемыми формами и динамическими списками. Многие разработчики сталкиваются с ситуацией, когда ради изменения одной незначительной настройки (например, видимости или доступности поля) приходится переносить в расширение конфигурации саму форму, что неизбежно влечет за собой «вагон и маленькую тележку» связанных объектов метаданных. Это усложняет поддержку и засоряет структуру проекта.
Давайте подробно проанализируем ситуацию, описанную автором на форуме, выясним технические причины необычного поведения платформы с кэшированием полей и найдем элегантные архитектурные способы решения этой задачи без перегрузки расширения лишними объектами.
Для начала выясним причину странного поведения формы, которое так удивило автора вопроса. Ситуация следующая: разработчик перенес форму в расширение, установил флаг «Использовать всегда» для реквизита Номенклатура, зашел в режиме «1С:Предприятие» и через команду «Изменить форму» вытащил на экран дочерний реквизит Артикул (через точку от Номенклатуры). Затем он удалил все изменения в расширении (вернул форму к исходному виду конфигурации-поставщика, где флаг снят). Но, к удивлению разработчика, поле Артикул на форме осталось и продолжило нормально отображаться!
Давайте разберем по шагам, почему платформа повела себя именно так. Здесь сработали одновременно два механизма платформы «1С:Предприятие»:
ПриАктивизацииСтроки через структуру ТекущиеДанные). Если же поле (или связанное с ним дочернее поле, такое как Артикул) выведено на форму пользователем визуально, платформа автоматически и в любом случае принудительно включает его в SQL-запрос и передает на клиент, полностью игнорируя отсутствие флага «Использовать всегда».Артикул, сама модифицировала динамический запрос к СУБД для получения этого поля и успешно вывела данные на экран.Важное предупреждение: этот эффект «магии» временный. Если этот же список откроет другой пользователь, у которого нет сохраненной ранее настройки формы с артикулом, он это поле не увидит. Более того, если вы сами сбросите настройки формы к стандартным (команда «Еще» – «Установить стандартные настройки»), поле артикула мгновенно и безвозвратно исчезнет, и вернуть его через «Изменить форму» без доработки конфигурации уже не получится.
Рассмотрим ситуацию, когда нам необходимо дать пользователю возможность самостоятельно выводить реквизиты «через точку» (например, Номенклатура.Артикул или Контрагент.ИНН), абсолютно не вмешиваясь в программный код и не создавая расширений. Это возможно, но только при выполнении одного обязательного условия.
Для того чтобы пользователь мог конструировать пути к данным через точку в окне «Изменить форму», в элементах формы динамического списка обязательно должно присутствовать само базовое ссылочное поле (например, Номенклатура или Ссылка). При этом совершенно неважно, включена ли его видимость на экране. Главное — чтобы элемент формы существовал.
Проанализируем алгоритм действий пользователя:
Номенклатура), раскрывает его структуру с помощью знака «плюс» и отмечает галочками те реквизиты, которые ему необходимы (например, Артикул, Код, Производитель).Если же разработчики при проектировании формы полностью исключили ссылочные поля из состава элементов формы (даже скрытых), кнопка «Добавить поля» останется заблокированной (серой), и пользователь самостоятельно решить эту задачу не сможет.
Теперь рассмотрим профессиональные подходы к решению этой задачи. Переносить всю форму целиком, ее реквизиты, связанные документы и справочники в расширение ради одной галочки — крайне плохая практика, которая приводит к конфликтам при обновлениях типовых конфигураций. Нам гораздо выгоднее решить задачу программно при помощи расширения.
Для того чтобы сделать реквизит доступным для вывода на форму через пользовательские настройки, нам достаточно программно взвести флаг «Использовать всегда». Для этого в расширении достаточно перехватить процедуру формы ПриСозданииНаСервере. Нам не нужно тащить за собой кучу объектов — мы переносим в расширение только саму форму (без ее реквизитов и связей), пишем одну строчку кода, и все!
Посмотрим на пример реализации обработчика:
&НаСервере
&После("ПриСозданииНаСервере")
Процедура Расш_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
// Указываем имя поля динамического списка, которое должно быть доступно всегда
Список.УстановитьОбязательноеИспользование("Номенклатура", Истина);
КонецПроцедуры
Этот метод УстановитьОбязательноеИспользование у динамического списка является штатным инструментом платформы. Он указывает системе, что поле Номенклатура должно гарантированно передаваться на клиент. После применения этого кода пользователь сможет без труда зайти в «Изменить форму», нажать кнопку «Добавить поля» на элементе «Список» и вывести артикул или любые другие свойства номенклатуры.
Бывают ситуации, когда нужного поля вообще нет в исходном запросе динамического списка (например, если запрос сложный, или поле является вычисляемым, или нам требуется вывести данные из совершенно другой связанной таблицы). В этом случае мы можем прямо «на лету» модифицировать текст запроса динамического списка и программно создать элемент формы для вывода этого значения.
Давайте разберем этот процесс по шагам и посмотрим на пример готового кода, который также помещается в обработчик ПриСозданииНаСервере в расширении:
&НаСервере
&После("ПриСозданииНаСервере")
Процедура Расш_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
// Шаг 1. Модифицируем текст запроса динамического списка.
// Находим ключевое слово ВЫБРАТЬ и вставляем после него получение артикула напрямую.
НовыйТекстЗапроса = СтрЗаменить(Список.ТекстЗапроса,
"ВЫБРАТЬ",
"ВЫБРАТЬ ОсновнаяТаблица.Номенклатура.Артикул КАК АртикулНоменклатуры, ");
Список.ТекстЗапроса = НовыйТекстЗапроса;
// Шаг 2. Проверяем, существует ли уже элемент формы, чтобы избежать дублирования
Если Элементы.Найти("СписокАртикулНоменклатуры") = Неопределено Тогда
// Программно добавляем колонку в таблицу динамического списка
НоваяКолонка = Элементы.Добавить("СписокАртикулНоменклатуры", Тип("ПолеФормы"), Элементы.Список);
НоваяКолонка.Вид = ВидПоляФормы.ПолеВвода;
НоваяКолонка.ПутьКДанным = "Список.АртикулНоменклатуры";
НоваяКолонка.Заголовок = "Артикул номенклатуры";
НоваяКолонка.Видимость = Истина; // Поле сразу отобразится у всех пользователей
КонецЕсли;
КонецПроцедуры
Использование этого способа полностью избавляет нас от необходимости модифицировать метаданные вручную в конфигураторе. Запрос динамического списка перестраивается динамически при запуске сеанса, колонка создается программно, а основная конфигурация остается легко обновляемой и чистой.
Таким образом, мы выяснили, что «исчезновение» и «появление» полей на форме тесно связано со спецификой кэширования пользовательских настроек в СУБД, а оптимальным путем доработки интерфейса является использование лаконичных программных методов в расширениях конфигурации вместо ручного переноса сложных форм и их зависимостей.