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