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