Как вывести реквизит динамического списка на управляемую форму в 1С без переноса лишних объектов в расширение?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Приветствуем вас, коллеги! Сегодня мы разберем одну очень интересную, на первый взгляд «мистическую» особенность работы платформы «1С:Предприятие 8.3» с управляемыми формами и динамическими списками. Многие разработчики сталкиваются с ситуацией, когда ради изменения одной незначительной настройки (например, видимости или доступности поля) приходится переносить в расширение конфигурации саму форму, что неизбежно влечет за собой «вагон и маленькую тележку» связанных объектов метаданных. Это усложняет поддержку и засоряет структуру проекта.

Давайте подробно проанализируем ситуацию, описанную автором на форуме, выясним технические причины необычного поведения платформы с кэшированием полей и найдем элегантные архитектурные способы решения этой задачи без перегрузки расширения лишними объектами.

Разгадка «аномалии» с оставшимся артикулом: почему так произошло?

Для начала выясним причину странного поведения формы, которое так удивило автора вопроса. Ситуация следующая: разработчик перенес форму в расширение, установил флаг «Использовать всегда» для реквизита Номенклатура, зашел в режиме «1С:Предприятие» и через команду «Изменить форму» вытащил на экран дочерний реквизит Артикул (через точку от Номенклатуры). Затем он удалил все изменения в расширении (вернул форму к исходному виду конфигурации-поставщика, где флаг снят). Но, к удивлению разработчика, поле Артикул на форме осталось и продолжило нормально отображаться!

Давайте разберем по шагам, почему платформа повела себя именно так. Здесь сработали одновременно два механизма платформы «1С:Предприятие»:

  1. Как на самом деле работает флаг «Использовать всегда». Этот флаг сообщает платформе, что значение поля необходимо принудительно получать из базы данных и передавать с сервера на клиент даже в том случае, если оно визуально не выведено на форму. Это требуется, например, если разработчик планирует обращаться к значению этого поля в коде модулей (в обработчиках событий типа ПриАктивизацииСтроки через структуру ТекущиеДанные). Если же поле (или связанное с ним дочернее поле, такое как Артикул) выведено на форму пользователем визуально, платформа автоматически и в любом случае принудительно включает его в SQL-запрос и передает на клиент, полностью игнорируя отсутствие флага «Использовать всегда».
  2. Работа системного хранилища настроек (кэш формы). Когда пользователь в режиме «1С:Предприятие» воспользовался меню «Еще» – «Изменить форму» и добавил поле артикула, эта настройка внешнего вида формы была сохранена в системном хранилище настроек (в разрезе конкретного пользователя и конкретной формы). После того как расширение было удалено, конфигурация вернулась к исходному состоянию. Однако сохраненная индивидуальная настройка формы пользователя никуда не делась. Платформа при открытии формы прочитала пользовательскую настройку из хранилища, обнаружила требование отобразить Артикул, сама модифицировала динамический запрос к СУБД для получения этого поля и успешно вывела данные на экран.

Важное предупреждение: этот эффект «магии» временный. Если этот же список откроет другой пользователь, у которого нет сохраненной ранее настройки формы с артикулом, он это поле не увидит. Более того, если вы сами сбросите настройки формы к стандартным (команда «Еще» – «Установить стандартные настройки»), поле артикула мгновенно и безвозвратно исчезнет, и вернуть его через «Изменить форму» без доработки конфигурации уже не получится.

Как пользователь может самостоятельно вытащить реквизит без изменения кода?

Рассмотрим ситуацию, когда нам необходимо дать пользователю возможность самостоятельно выводить реквизиты «через точку» (например, Номенклатура.Артикул или Контрагент.ИНН), абсолютно не вмешиваясь в программный код и не создавая расширений. Это возможно, но только при выполнении одного обязательного условия.

Для того чтобы пользователь мог конструировать пути к данным через точку в окне «Изменить форму», в элементах формы динамического списка обязательно должно присутствовать само базовое ссылочное поле (например, Номенклатура или Ссылка). При этом совершенно неважно, включена ли его видимость на экране. Главное — чтобы элемент формы существовал.

Проанализируем алгоритм действий пользователя:

  1. Пользователь нажимает кнопку «Еще» в командной панели списка и выбирает пункт «Изменить форму...».
  2. В открывшемся дереве элементов формы необходимо спозиционироваться на элементе «Список» (или «Таблица»).
  3. На панели инструментов окна настройки формы станет активной кнопка «Добавить поля».
  4. В открывшемся списке доступных полей пользователь находит нужное ссылочное поле (например, Номенклатура), раскрывает его структуру с помощью знака «плюс» и отмечает галочками те реквизиты, которые ему необходимы (например, Артикул, Код, Производитель).
  5. После нажатия кнопки «ОК» выбранные поля добавляются в структуру формы, и их можно позиционировать в удобном порядке.

Если же разработчики при проектировании формы полностью исключили ссылочные поля из состава элементов формы (даже скрытых), кнопка «Добавить поля» останется заблокированной (серой), и пользователь самостоятельно решить эту задачу не сможет.

Правильные способы решения задачи в расширении без «вагона объектов»

Теперь рассмотрим профессиональные подходы к решению этой задачи. Переносить всю форму целиком, ее реквизиты, связанные документы и справочники в расширение ради одной галочки — крайне плохая практика, которая приводит к конфликтам при обновлениях типовых конфигураций. Нам гораздо выгоднее решить задачу программно при помощи расширения.

Способ А. Программная установка обязательного использования поля

Для того чтобы сделать реквизит доступным для вывода на форму через пользовательские настройки, нам достаточно программно взвести флаг «Использовать всегда». Для этого в расширении достаточно перехватить процедуру формы ПриСозданииНаСервере. Нам не нужно тащить за собой кучу объектов — мы переносим в расширение только саму форму (без ее реквизитов и связей), пишем одну строчку кода, и все!

Посмотрим на пример реализации обработчика:


&НаСервере
&После("ПриСозданииНаСервере")
Процедура Расш_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
    
    // Указываем имя поля динамического списка, которое должно быть доступно всегда
    Список.УстановитьОбязательноеИспользование("Номенклатура", Истина);
    
КонецПроцедуры

Этот метод УстановитьОбязательноеИспользование у динамического списка является штатным инструментом платформы. Он указывает системе, что поле Номенклатура должно гарантированно передаваться на клиент. После применения этого кода пользователь сможет без труда зайти в «Изменить форму», нажать кнопку «Добавить поля» на элементе «Список» и вывести артикул или любые другие свойства номенклатуры.

Способ Б. Динамическая модификация запроса и добавление колонки

Бывают ситуации, когда нужного поля вообще нет в исходном запросе динамического списка (например, если запрос сложный, или поле является вычисляемым, или нам требуется вывести данные из совершенно другой связанной таблицы). В этом случае мы можем прямо «на лету» модифицировать текст запроса динамического списка и программно создать элемент формы для вывода этого значения.

Давайте разберем этот процесс по шагам и посмотрим на пример готового кода, который также помещается в обработчик ПриСозданииНаСервере в расширении:


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

Использование этого способа полностью избавляет нас от необходимости модифицировать метаданные вручную в конфигураторе. Запрос динамического списка перестраивается динамически при запуске сеанса, колонка создается программно, а основная конфигурация остается легко обновляемой и чистой.

Таким образом, мы выяснили, что «исчезновение» и «появление» полей на форме тесно связано со спецификой кэширования пользовательских настроек в СУБД, а оптимальным путем доработки интерфейса является использование лаконичных программных методов в расширениях конфигурации вместо ручного переноса сложных форм и их зависимостей.

← На главную