При разработке в среде обычных форм 1С программисты часто сталкиваются с задачей выгрузки данных из элемента управления ТабличноеПоле в объект ТаблицаЗначений. Сложность возникает в тех случаях, когда табличное поле содержит вычисляемые колонки, не привязанные к реквизитам исходной табличной части и заполняемые динамически в обработчиках событий ПриВыводеСтроки или ПриПолученииДанных. Разберем архитектурные особенности работы с табличным полем и эффективные способы решения этой задачи.
Проанализируем, почему нельзя напрямую прочитать данные всех колонок из визуального элемента:
ТабличноеПоле отвечает исключительно за визуализацию информации на экране. Колонки, у которых свойство Данные оставлено пустым, физически отсутствуют в источнике данных (в табличной части документа или справочника).ОформлениеСтроки() предназначен для настройки внешнего вида ячеек, которые отрисовываются в интерфейсе. Попытка обойти все строки таблицы через обращение к свойствам ячеек оформления не сработает для строк за пределами видимой области экрана и приведет к серьезному падению производительности интерфейса.Рассмотрим классический способ получения данных. Сначала выгрузим исходную табличную часть документа в таблицу значений, добавим недостающие колонки и заполним их отдельным программным алгоритмом.
Разберем реализацию по шагам:
Выгрузить().Колонки таблицы значений требуемые расчетные поля.ПриВыводеСтроки.Посмотрим на пример программного кода:
// Выгружаем базовую табличную часть в таблицу значений
ТЗДанные = ЭтотОбъект.Товары.Выгрузить();
// Добавляем отсутствующие в табличной части колонки
ТЗДанные.Колонки.Добавить("ОстатокНаСкладе", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));
ТЗДанные.Колонки.Добавить("ТекущаяЦена", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));
// Заполняем вычисляемые поля
Для Каждого СтрТЗ Из ТЗДанные Цикл
// Вызываем функцию расчета, переиспользуя логику из ПриВыводеСтроки
СтрТЗ.ОстатокНаСкладе = ПолучитьОстатокПоНоменклатуре(СтрТЗ.Номенклатура, ЭтотОбъект.Склад);
СтрТЗ.ТекущаяЦена = ПолучитьЦенуНоменклатуры(СтрТЗ.Номенклатура, ЭтотОбъект.ТипЦен, ЭтотОбъект.Дата);
КонецЦикла;
Если расчет дополнительных колонок связан с обращением к регистрам сведений, накопления или остаткам, выполнять расчет построчно в цикле крайне неэффективно. Оптимальным решением является обработка всей таблицы с помощью объекта Запрос и менеджера временных таблиц.
Рассмотрим подробнее данный подход:
ТЗДанные = ЭтотОбъект.Товары.Выгрузить();
Запрос = Новый Запрос;
МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос.Текст =
"ВЫБРАТЬ
| ТЗ.НомерСтроки КАК НомерСтроки,
| ТЗ.Номенклатура КАК Номенклатура,
| ТЗ.Количество КАК Количество,
| ТЗ.Цена КАК Цена,
| ТЗ.Сумма КАК Сумма
|ПОМЕСТИТЬ ВТ_Товары
|ИЗ
| &ТаблицаТовары КАК ТЗ
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ.НомерСтроки КАК НомерСтроки,
| ВТ.Номенклатура КАК Номенклатура,
| ВТ.Количество КАК Количество,
| ВТ.Цена КАК Цена,
| ВТ.Сумма КАК Сумма,
| ЕСТЬNULL(Остатки.ВНаличииОстаток, 0) КАК ОстатокНаСкладе,
| ЕСТЬNULL(Цены.Цена, 0) КАК ТекущаяЦена
|ИЗ
| ВТ_Товары КАК ВТ
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Склад = &Склад) КАК Остатки
| ПО ВТ.Номенклатура = Остатки.Номенклатура
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ТипЦен = &ТипЦен) КАК Цены
| ПО ВТ.Номенклатура = Цены.Номенклатура
|УПОРЯДОЧИТЬ ПО
| НомерСтроки";
Запрос.УстановитьПараметр("ТаблицаТовары", ТЗДанные);
Запрос.УстановитьПараметр("Период", ЭтотОбъект.Дата);
Запрос.УстановитьПараметр("Склад", ЭтотОбъект.Склад);
Запрос.УстановитьПараметр("ТипЦен", ЭтотОбъект.ТипЦен);
// Получаем готовую таблицу значений со всеми заполненными колонками
РезультатТаблица = Запрос.Выполнить().Выгрузить();
Если в табличном поле пользователем был установлен отбор (коллекция ОтборСтрок), стандартный метод Выгрузить() вернет абсолютно все строки табличной части без учета фильтрации. Чтобы получить только видимые строки, применим ПостроительЗапроса.
Разберем по шагам работу с построителем:
ПостроительЗапроса и передадим ему описание источника данных.ОтборСтрок табличного поля.Посмотрим на пример кода:
// Создаем источник данных на основе табличной части
ИсточникДанных = Новый ОписаниеИсточникаДанных(ЭтотОбъект.Товары);
Построитель = Новый ПостроительЗапроса;
Построитель.ИсточникДанных = ИсточникДанных;
// Переносим настройки фильтрации из табличного поля
Для Каждого ЭлементОтбора Из ЭлементыФормы.Товары.ОтборСтрок Цикл
Если ЭлементОтбора.Использование Тогда
НовыйОтбор = Построитель.Отбор.Добавить(ЭлементОтбора.Имя);
ЗаполнитьЗначенияСвойств(НовыйОтбор, ЭлементОтбора);
КонецЕсли;
КонецЦикла;
// Выполняем построитель и выгружаем только отфильтрованные строки
Построитель.Выполнить();
ТЗОтфильтрованная = Построитель.Результат.Выгрузить();
Если форма требует постоянной работы с большим объемом вычисляемых данных, рекомендуем пересмотреть организацию данных в форме:
ТаблицаЗначений. В этом случае все расчетные колонки физически присутствуют в таблице, и выгрузка выполняется простым методом ТаблицаЗначений.Скопировать().ПриПолученииДанных), сохраняя результаты во временной структуре или таблице соответствий в модуле формы. При необходимости выгрузки данные быстро объединяются по ключевым полям без повторных тяжелых запросов.