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