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

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

При разработке сложных интерфейсов на управляемых формах 1С часто возникает необходимость динамически добавлять элементы: страницы (вкладки), поля ввода или кнопки. Однако начинающие разработчики часто сталкиваются с проблемой: элементы создаются "на лету", но после записи документа и закрытия формы они бесследно исчезают вместе с введенными данными. В этой статье мы подробно разберем, как правильно реализовать динамический интерфейс, чтобы он корректно работал и сохранял информацию в базе данных.

Анализ жизненного цикла динамических элементов

Для начала проанализируем, почему программно созданные элементы пропадают. В системе 1С:Предприятие 8 программные элементы формы (страницы, декорации, кнопки) существуют только в оперативной памяти текущего сеанса работы с формой. Как только форма закрывается, всё, что было создано через коллекцию Элементы.Добавить(), уничтожается. Платформа не запоминает структуру формы, если она не описана в конфигураторе статически.

Чтобы форма выглядела одинаково при каждом открытии, мы должны повторно выполнять код по созданию элементов в процедуре ПриСозданииНаСервере. Если же элементы должны появляться в ответ на действия пользователя (например, при выборе значения в поле), нам нужно сохранить текущее "состояние" (количество страниц или список менеджеров) в реквизитах самого объекта, чтобы при следующем открытии код "знал", что именно нужно восстановить.

Разберем по шагам: как правильно инициализировать элементы

Рассмотрим ситуацию, когда при изменении списка менеджеров в документе должны создаваться соответствующие вкладки с полями ввода. Рассмотрим типичную ошибку: создание элементов только в событии ПриИзменении. Если мы так поступим, то при повторном открытии документа форма будет пустой. Выясним причину: событие ПриИзменении уже не сработает автоматически, а в процедуре ПриСозданииНаСервере кода по отрисовке элементов нет.

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


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // Восстанавливаем динамический интерфейс на основе данных объекта
    ОбновитьДинамическиеСтраницы();
КонецПроцедуры

&НаСервере
Процедура МенеджерыПриИзмененииНаСервере()
    // Перерисовываем интерфейс при изменении данных
    ОбновитьДинамическиеСтраницы();
КонецПроцедуры

&НаСервере
Процедура ОбновитьДинамическиеСтраницы()
    // Здесь располагается логика удаления старых и создания новых элементов
    // Используем Элементы.Добавить(...) и ИзменитьРеквизиты(...)
КонецПроцедуры

Проблема сохранения данных: Реквизиты формы vs Реквизиты объекта

Часто разработчики используют метод ИзменитьРеквизиты() для создания новых полей. Важно понимать: созданные таким образом реквизиты формы никак не связаны с базой данных автоматически. Это лишь временные переменные в памяти формы. Чтобы данные из этих полей (например, список поставщиков на странице менеджера) попали в документ, необходимо выполнить привязку к реальным метаданным.

Проанализируем два способа решения этой задачи:

  1. Использование табличных частей объекта: Это самый надежный способ. Мы создаем в документе табличную часть (например, ПоставщикиПоМенеджерам), где храним связь "Менеджер — Поставщик". При создании динамического поля на форме мы указываем его ПутьКДанным напрямую к строке этой табличной части.
  2. Программная перекладка данных: Если мы все же создаем временные реквизиты формы через ИзменитьРеквизиты, нам придется вручную переносить значения из этих реквизитов в объект 1С перед записью (в обработчике ПередЗаписьюНаСервере) и обратно при открытии формы.

Рассмотрим подробнее использование Пути к данным (DataPath)

Выясним, как связать программное поле с данными так, чтобы платформа сама заботилась о сохранении. Если у вас в объекте есть табличная часть, вы можете обращаться к её данным через индекс или через связь с текущей строкой. Посмотрим на пример кода, где мы добавляем поле ввода и привязываем его к реквизиту объекта:


// Предположим, у нас есть ТЧ "Менеджеры" в документе
Для Каждого СтрокаТЧ Из Объект.Менеджеры Цикл
    ИмяЭлемента = "ПолеМенеджера_" + СтрокаТЧ.НомерСтроки;
    НовыйЭлемент = Элементы.Добавить(ИмяЭлемента, Тип("ПолеФормы"), ГруппаСтраница);
    НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
    
    // Прямая привязка к данным объекта в табличной части
    // Индексация в ПутьКДанным начинается с 0
    НовыйЭлемент.ПутьКДанным = "Объект.Менеджеры[" + (СтрокаТЧ.НомерСтроки - 1) + "].Менеджер";
КонецЦикла;

Важный момент: использование прямой индексации (Объект.Менеджеры[0]) может быть рискованным, если строки в табличной части могут удаляться или перемещаться. В таких случаях надежнее создавать реквизиты формы, которые будут служить "прослойкой".

Оптимизация работы с методом ИзменитьРеквизиты

Метод ИзменитьРеквизиты является ресурсоемким. При каждом его вызове форма полностью перегенерируется на сервере. Если вызывать его в цикле для каждого нового поля, интерфейс начнет заметно "подтормаживать".

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

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

Использование динамических команд

Если на динамических страницах нужны кнопки (например, "Добавить поставщиков"), команды для них также нужно создавать программно. Посмотрим на пример:


ИмяКоманды = "КомандаДействия_" + Индекс;
НоваяКоманда = ЭтаФорма.Команды.Добавить(ИмяКоманды);
НоваяКоманда.Действие = "ОбщийОбработчикНажатияКнопки";
НоваяКоманда.Заголовок = "Выполнить действие";

НоваяКнопка = Элементы.Добавить("Кнопка_" + Индекс, Тип("КнопкаФормы"), Группа);
НоваяКнопка.ИмяКоманды = ИмяКоманда;

В процедуре ОбщийОбработчикНажатияКнопки(Команда), которая должна быть описана в модуле формы с директивой &НаКлиенте, мы можем определить, какая именно кнопка была нажата, анализируя параметр Команда.Имя.

Заключение и рекомендации

Мы проанализировали основные сложности динамического построения интерфейса в 1С. Подведем итоги: чтобы данные не пропадали, интерфейс должен пересоздаваться в ПриСозданииНаСервере, а пути к данным элементов должны вести либо к реквизитам объекта (ТЧ, доп. реквизиты), либо к реквизитам формы, значения которых вы сознательно синхронизируете с объектом базы данных.

Однако, прежде чем приступать к сложному программному коду, всегда стоит рассмотреть классическую схему. В большинстве случаев задачу можно решить стандартными табличными частями и статическими элементами формы. Это упростит поддержку кода и повысит стабильность работы системы. Программное создание элементов оправдано только тогда, когда интерфейс должен кардинально меняться в зависимости от внешних настроек, которые невозможно предусмотреть на этапе проектирования.

← На главную