В практике разработчика 1С часто возникают задачи, когда структура формы не может быть определена заранее в конфигураторе. Например, при создании универсальных обработок для загрузки данных из Excel, построении динамических опросников или интерактивных отчетов, где количество колонок зависит от входных данных. В таких случаях мы прибегаем к механизму программного изменения состава реквизитов и элементов формы.
Разберем детально, как реализовать этот механизм, какие функции платформы 1С:Предприятие 8.3 нам понадобятся и каких ошибок следует избегать при работе с большими объемами данных.
Процесс создания динамического интерфейса всегда состоит из двух концептуально разных этапов: создание данных (реквизитов) и создание визуальных элементов (полей ввода, флажков и т.д.). Рассмотрим первый этап — работу с программным интерфейсом формы.
Для добавления реквизитов используется метод ИзменитьРеквизиты(). Проанализируем типичную ситуацию: нам нужно создать N строковых реквизитов. Важно помнить, что метод ИзменитьРеквизиты() является крайне ресурсоемким, так как инициирует пересборку всей структуры формы. Поэтому крайне не рекомендуется вызывать его внутри цикла. Правильный подход — сначала собрать все новые реквизиты в массив, а затем вызвать метод один раз.
Рассмотрим пример кода:
&НаСервере
Процедура СоздатьРеквизитыНаСервере(Количество)
НовыеРеквизиты = Новый Массив;
// Подготовим описание типа для наших будущих реквизитов
МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("Строка"));
ОписаниеТипаСтрока = Новый ОписаниеТипов(МассивТипов, , Новый КвалификаторыСтроки(100));
Для Счетчик = 1 По Количество Цикл
ИмяРеквизита = "ДинамическийРеквизит_" + Счетчик;
ЗаголовокРеквизита = "Поле №" + Счетчик;
// Создаем объект РеквизитФормы
// Параметры: Имя, Тип, Путь, Заголовок, СохраняемыеДанные
НовыйРеквизит = Новый РеквизитФормы(ИмяРеквизита, ОписаниеТипаСтрока, , ЗаголовокРеквизита, Истина);
НовыеРеквизиты.Добавить(НовыйРеквизит);
КонецЦикла;
// Вызываем изменение структуры формы один раз вне цикла
ЭтаФорма.ИзменитьРеквизиты(НовыеРеквизиты);
КонецПроцедуры
В данном примере мы используем объект РеквизитФормы. Обратите внимание на последний параметр Истина — он указывает платформе, что данные этого реквизита должны участвовать в механизме отслеживания модифицированности формы.
После того как реквизиты созданы в памяти сервера, пользователь их все еще не видит. Чтобы они появились в интерфейсе, нам нужно программно создать элементы формы (например, ПолеФормы) и связать их с созданными реквизитами через свойство ПутьКДанным.
Продолжим наш пример и добавим цикл создания визуальных элементов:
&НаСервере
Процедура ОтрисоватьЭлементыНаФорме(Количество)
Для Счетчик = 1 По Количество Цикл
ИмяРеквизита = "ДинамическийРеквизит_" + Счетчик;
ИмяЭлемента = "ПолеВвода_" + Счетчик;
// Добавляем элемент на форму
// Параметры: Имя, Тип, Родитель
НовыйЭлемент = ЭтаФорма.Элементы.Добавить(ИмяЭлемента, Тип("ПолеФормы"), ЭтаФорма);
// Указываем связь с данными
НовыйЭлемент.ПутьКДанным = ИмяРеквизита;
// Настраиваем внешний вид
НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
НовыйЭлемент.Заголовок = "Введите значение " + Счетчик;
КонецЦикла;
КонецПроцедуры
При использовании метода Элементы.Добавить() третьим параметром мы передаем родительский контейнер. Если мы хотим, чтобы поля располагались не просто списком, а, например, в определенной группе или на странице панели, нам нужно сначала создать эту группу (тип ГруппаФормы), а затем передавать её в качестве родителя для полей ввода.
Рассмотрим ситуацию, описанную в обсуждении: что если количество полей достигает 200, 1000 или более? Здесь мы сталкиваемся с несколькими проблемами:
Выясним, как профессионально решить задачу, если нужно хранить сотни произвольных параметров. Вместо создания сотен отдельных реквизитов целесообразно использовать паттерн EAV (Entity-Attribute-Value).
Если ваша задача — хранить 200 столбцов из Excel, которые могут меняться, лучше не менять структуру базы данных или формы динамически, а использовать РегистрСведений. Создайте регистр со следующей структурой:
ХранилищеЗначения или составной тип).В этом случае на форме вместо создания 200 реквизитов вы создаете одну Таблицу Значений. Вы прописываете логику, которая при открытии формы считывает данные из регистра и заполняет колонки таблицы. Это работает значительно быстрее и стабильнее, чем создание индивидуальных элементов управления для каждого параметра.
Проанализируем еще один важный момент: как заставить динамически созданное поле реагировать на действия пользователя? Для этого используется метод УстановитьДействие().
Допустим, нам нужно, чтобы при изменении любого из 200 полей выполнялась какая-то логика. Мы должны заранее создать в модуле формы экспортную процедуру, а затем привязать её к каждому элементу:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// ... код создания реквизитов и элементов ...
НовыйЭлемент.УстановитьДействие("ПриИзменении", "Подключаемый_ПриИзмененииДинамическогоПоля");
КонецПроцедуры
&НаКлиенте
Процедура Подключаемый_ПриИзмененииДинамическогоПоля(Элемент)
Сообщить("Вы изменили поле: " + Элемент.Имя);
// Значение можно получить через ЭтаФорма[Элемент.ПутьКДанным]
КонецПроцедуры
Программное создание реквизитов — мощный инструмент, который требует аккуратности. Основные правила работы:
ИзменитьРеквизиты() один раз, передавая в него массив всех добавляемых (и удаляемых) объектов.Элемент с данными через ПутьКДанным.ТаблицыЗначений или модели данных EAV через регистры сведений.ГруппаФормы с видом ГруппаФормыВид.ОбычнаяГруппа или Страницы.Используя эти методы, вы сможете создавать гибкие и адаптивные интерфейсы, способные подстраиваться под любые задачи бизнеса, сохраняя при этом высокую производительность системы.