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