Как программно создать произвольное количество реквизитов и элементов на форме в 1С?

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

В практике разработчика 1С часто возникают задачи, когда структура формы не может быть определена заранее в конфигураторе. Например, при создании универсальных обработок для загрузки данных из Excel, построении динамических опросников или интерактивных отчетов, где количество колонок зависит от входных данных. В таких случаях мы прибегаем к механизму программного изменения состава реквизитов и элементов формы.

Разберем детально, как реализовать этот механизм, какие функции платформы 1С:Предприятие 8.3 нам понадобятся и каких ошибок следует избегать при работе с большими объемами данных.

Пошаговый алгоритм создания динамических реквизитов

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

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

Рассмотрим пример кода:


&НаСервере
Процедура СоздатьРеквизитыНаСервере(Количество)

    НовыеРеквизиты = Новый Массив;
    
    // Подготовим описание типа для наших будущих реквизитов
    МассивТипов = Новый Массив;
    МассивТипов.Добавить(Тип("Строка"));
    ОписаниеТипаСтрока = Новый ОписаниеТипов(МассивТипов, , Новый КвалификаторыСтроки(100));

    Для Счетчик = 1 По Количество Цикл
        ИмяРеквизита = "ДинамическийРеквизит_" + Счетчик;
        ЗаголовокРеквизита = "Поле №" + Счетчик;
        
        // Создаем объект РеквизитФормы
        // Параметры: Имя, Тип, Путь, Заголовок, СохраняемыеДанные
        НовыйРеквизит = Новый РеквизитФормы(ИмяРеквизита, ОписаниеТипаСтрока, , ЗаголовокРеквизита, Истина);
        НовыеРеквизиты.Добавить(НовыйРеквизит);
    КонецЦикла;

    // Вызываем изменение структуры формы один раз вне цикла
    ЭтаФорма.ИзменитьРеквизиты(НовыеРеквизиты);

КонецПроцедуры

В данном примере мы используем объект РеквизитФормы. Обратите внимание на последний параметр Истина — он указывает платформе, что данные этого реквизита должны участвовать в механизме отслеживания модифицированности формы.

Создание и отображение элементов на форме

После того как реквизиты созданы в памяти сервера, пользователь их все еще не видит. Чтобы они появились в интерфейсе, нам нужно программно создать элементы формы (например, ПолеФормы) и связать их с созданными реквизитами через свойство ПутьКДанным.

Продолжим наш пример и добавим цикл создания визуальных элементов:


&НаСервере
Процедура ОтрисоватьЭлементыНаФорме(Количество)

    Для Счетчик = 1 По Количество Цикл
        ИмяРеквизита = "ДинамическийРеквизит_" + Счетчик;
        ИмяЭлемента = "ПолеВвода_" + Счетчик;
        
        // Добавляем элемент на форму
        // Параметры: Имя, Тип, Родитель
        НовыйЭлемент = ЭтаФорма.Элементы.Добавить(ИмяЭлемента, Тип("ПолеФормы"), ЭтаФорма);
        
        // Указываем связь с данными
        НовыйЭлемент.ПутьКДанным = ИмяРеквизита;
        
        // Настраиваем внешний вид
        НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
        НовыйЭлемент.Заголовок = "Введите значение " + Счетчик;
    КонецЦикла;

КонецПроцедуры

При использовании метода Элементы.Добавить() третьим параметром мы передаем родительский контейнер. Если мы хотим, чтобы поля располагались не просто списком, а, например, в определенной группе или на странице панели, нам нужно сначала создать эту группу (тип ГруппаФормы), а затем передавать её в качестве родителя для полей ввода.

Оптимизация и ограничения при работе с большим количеством полей

Рассмотрим ситуацию, описанную в обсуждении: что если количество полей достигает 200, 1000 или более? Здесь мы сталкиваемся с несколькими проблемами:

  1. Производительность интерфейса: Каждый элемент формы — это объект в DOM-дереве браузера (в веб-клиенте) или объект графической подсистемы Windows. При создании 1000 полей ввода форма будет открываться крайне медленно, а прокрутка станет "тяжелой".
  2. Передача данных: Все динамические реквизиты передаются между сервером и клиентом при каждом контекстном вызове. Большой объем данных замедлит работу пользователя.
  3. Ограничение на изменение метаданных: Программное создание реквизитов формы не создает колонки в таблицах базы данных (SQL). Это лишь временные данные сеанса.

Выясним, как профессионально решить задачу, если нужно хранить сотни произвольных параметров. Вместо создания сотен отдельных реквизитов целесообразно использовать паттерн EAV (Entity-Attribute-Value).

Альтернативный подход: Модель "Сущность-Атрибут-Значение"

Если ваша задача — хранить 200 столбцов из Excel, которые могут меняться, лучше не менять структуру базы данных или формы динамически, а использовать РегистрСведений. Создайте регистр со следующей структурой:

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

Обработка событий динамических элементов

Проанализируем еще один важный момент: как заставить динамически созданное поле реагировать на действия пользователя? Для этого используется метод УстановитьДействие().

Допустим, нам нужно, чтобы при изменении любого из 200 полей выполнялась какая-то логика. Мы должны заранее создать в модуле формы экспортную процедуру, а затем привязать её к каждому элементу:


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

&НаКлиенте
Процедура Подключаемый_ПриИзмененииДинамическогоПоля(Элемент)
    Сообщить("Вы изменили поле: " + Элемент.Имя);
    // Значение можно получить через ЭтаФорма[Элемент.ПутьКДанным]
КонецПроцедуры

Подведем итоги

Программное создание реквизитов — мощный инструмент, который требует аккуратности. Основные правила работы:

  1. Всегда используйте ИзменитьРеквизиты() один раз, передавая в него массив всех добавляемых (и удаляемых) объектов.
  2. Не забывайте связывать визуальный Элемент с данными через ПутьКДанным.
  3. Если полей больше 50-100, задумайтесь об использовании ТаблицыЗначений или модели данных EAV через регистры сведений.
  4. Для группировки элементов используйте программное создание объектов типа ГруппаФормы с видом ГруппаФормыВид.ОбычнаяГруппа или Страницы.

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

← На главную