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