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