При работе с управляемыми формами 1С начинающие разработчики часто сталкиваются с ситуацией, когда динамически созданные элементы — страницы, поля ввода или кнопки — бесследно исчезают после закрытия и повторного открытия документа. Рассмотрим подробнее, почему это происходит и как правильно организовать хранение данных и восстановление интерфейса.
Прежде всего, разберем архитектуру управляемого приложения. Когда вы программно добавляете элемент через Элементы.Добавить() или создаете реквизит формы через ИзменитьРеквизиты(), эти изменения происходят только в оперативной памяти текущего сеанса работы формы. Они не записываются в метаданные конфигурации. Как только форма закрывается, её «виртуальная» структура уничтожается.
При повторном открытии платформа 1С строит форму заново, основываясь на том, что жестко задано в конфигураторе. Если в процедуре ПриСозданииНаСервере нет кода, который заново «отрисует» ваши страницы, пользователь их не увидит. Проанализируем ситуацию: данные могут быть записаны в базу, но визуальных средств для их отображения в новой форме еще не создано.
Программно созданные реквизиты формы (через ИзменитьРеквизиты) не умеют автоматически сохраняться в базу данных. Чтобы данные «выжили» после закрытия формы, они должны быть привязаны к физическим реквизитам объекта (документа). Для динамических наборов данных лучше всего подходят Табличные части.
Создадим в документе табличную часть, например, ДополнительныеРеквизиты с колонками:
ИмяРеквизита (Строка) — чтобы знать, куда вернуть данные.Значение (Любой тип или строка) — для хранения самого значения.КлючСвязи (Число или Ссылка) — если данные нужно привязать к конкретной странице или менеджеру.Метод ИзменитьРеквизиты является довольно тяжелым для системы, так как вызывает полную перегенерацию контекста формы. Проанализируем пример кода, который позволяет добавить массив реквизитов за один раз, что значительно ускоряет работу:
&НаСервере
Процедура СоздатьДинамическиеРеквизиты(Количество)
МассивДобавляемыхРеквизитов = Новый Массив;
Для Сч = 1 По Количество Цикл
ИмяРеквизита = "ДинамическийРеквизит_" + Сч;
// Описываем тип данных (например, СправочникСсылка.Партнеры)
МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("СправочникСсылка.Партнеры"));
ОписаниеТипа = Новый ОписаниеТипов(МассивТипов);
НовыйРеквизит = Новый РеквизитФормы(ИмяРеквизита, ОписаниеТипа, , "Поставщик " + Сч, Истина);
МассивДобавляемыхРеквизитов.Добавить(НовыйРеквизит);
КонецЦикла;
// Добавляем реквизиты в структуру формы
ЭтаФорма.ИзменитьРеквизиты(МассивДобавляемыхРеквизитов);
КонецПроцедуры
После того как реквизиты созданы в памяти, их нужно отобразить. Выясним причину, по которой данные в полях могут не отображаться: важно правильно указать ПутьКДанным. Рассмотрим пример создания страницы и поля на ней:
&НаСервере
Процедура СоздатьЭлементыИнтерфейса(Сч)
ИмяСтраницы = "СтраницаМенеджера_" + Сч;
НоваяСтраница = Элементы.Добавить(ИмяСтраницы, Тип("ГруппаФормы"), Элементы.ГруппаСтраницы);
НоваяСтраница.Вид = ВидГруппыФормы.Страница;
НоваяСтраница.Заголовок = "Менеджер " + Сч;
ИмяПоля = "ПолеВвода_" + Сч;
НовоеПоле = Элементы.Добавить(ИмяПоля, Тип("ПолеФормы"), НоваяСтраница);
НовоеПоле.Вид = ВидПоляФормы.ПолеВвода;
// Указываем путь к динамически созданному реквизиту
НовоеПоле.ПутьКДанным = "ДинамическийРеквизит_" + Сч;
КонецПроцедуры
Это самый важный этап. Вызовем логику построения формы в событии ПриСозданииНаСервере. Мы должны прочитать данные из табличной части объекта и на их основе воссоздать структуру элементов. Проанализируем алгоритм:
Объект.ДополнительныеРеквизиты.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Восстанавливаем структуру по сохраненным данным
Если Объект.МенеджерыПоСнабжению.Количество() > 0 Тогда
// 1. Сначала создаем все необходимые реквизиты в памяти
СоздатьДинамическиеРеквизиты(Объект.МенеджерыПоСнабжению.Количество());
// 2. Затем создаем визуальные элементы и заполняем их данными
Сч = 1;
Для Каждого СтрокаТЧ Из Объект.МенеджерыПоСнабжению Цикл
СоздатьЭлементыИнтерфейса(Сч);
// Заполняем созданный реквизит формы значением из ТЧ объекта
ЭтаФорма["ДинамическийРеквизит_" + Сч] = СтрокаТЧ.ЗначениеПоставщика;
Сч = Сч + 1;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Чтобы данные из «виртуальных» полей попали в базу, их нужно перенести обратно в объект перед записью. Разберем работу обработчика ПередЗаписьюНаСервере:
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Очищаем старые данные в объекте и записываем актуальные из формы
ТекущийОбъект.МенеджерыПоСнабжению.Очистить();
// В реальном коде стоит использовать счетчик или массив имен реквизитов
Для Сч = 1 По МаксимальноеКоличествоЦикла Цикл
ИмяРеквизита = "ДинамическийРеквизит_" + Сч;
// Проверяем, существует ли такой реквизит на форме
ЗначениеДляЗаписи = ЭтаФорма[ИмяРеквизита];
Если ЗначениеЗаполнено(ЗначениеДляЗаписи) Тогда
НоваяСтрока = ТекущийОбъект.МенеджерыПоСнабжению.Добавить();
НоваяСтрока.ЗначениеПоставщика = ЗначениеДляЗаписи;
НоваяСтрока.ИмяРеквизита = ИмяРеквизита;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Посмотрим на ситуацию шире: ручное управление динамическими реквизитами — трудоемкий процесс, чреватый ошибками при обновлении конфигурации или изменении типов данных. Рассмотрим альтернативные подходы:
Сохранение настроек в свойствах формы, выбрав режим Использовать список. Однако помните, что настройки формы не являются данными документа и не видны другим пользователям.Таким образом, для успешного сохранения данных в динамических формах необходимо четко разделять визуальное представление (создается в ПриСозданииНаСервере) и физическое хранение (табличные части Объект).