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