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