Как реализовать отбор строк в подчиненном табличном поле с типом ТаблицаЗначений в 1С?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При разработке интерфейсов на платформе «1С:Предприятие» часто возникает задача связывания двух табличных полей по принципу «главный — подчиненный». Однако если в качестве источника данных выступают не табличные части объектов метаданных, а динамически созданные коллекции типа ТаблицаЗначений, разработчики сталкиваются с ограничением платформы: у реквизитов формы с типом ТаблицаЗначений отсутствует встроенное свойство ОтборСтрок.

Разберем детально, почему возникает эта проблема, и какие существуют эффективные способы фильтрации подчиненных строк при вызове события ПриАктивацииСтроки() главного табличного поля.

Причины проблемы и ограничения платформы

Выясним основные причины, по которым стандартные механизмы отбора не работают с таблицами значений:

  1. Отсутствие свойства отбора: В отличие от элементных расширений для табличных частей объектов метаданных, элемент «Табличное поле», связанный с объектом ТаблицаЗначений, не имеет встроенного свойства ОтборСтрок.
  2. Неактивные стандартные кнопки: Стандартная кнопка командной панели «Установить отбор и сортировку списка» для такого табличного поля недоступна.
  3. Типизация источника данных: Метод НайтиСтроки() объекта ТаблицаЗначений возвращает объект типа Массив. Связать элемент формы напрямую с массивом нельзя, так как табличное поле требует коллекцию типа ТаблицаЗначений.
  4. Особенности синхронизации: При выполнении метода Скопировать() создаются новые независимые экземпляры строк. Если пользователь редактирует отфильтрованные данные в подчиненном табличном поле, эти изменения не попадают автоматически в исходную таблицу — требуется дополнительная логика обратной синхронизации.

Способ 1. Разделение на хранилище данных и подчиненную таблицу для отображения

Рассмотрим наиболее распространённый способ решения задачи. В контексте формы создаются два реквизита: полная подчиненная таблица значений (хранилище всех подчиненных строк) и отображаемая таблица значений, привязанная к табличному полю формы.

При смене текущей строки в главном табличном поле вызывается обработчик события ПриАктивацииСтроки(), который фильтрует исходные данные и перезаполняет подчиненное табличное поле.

Проанализируем пример кода с использованием метода Скопировать():


Процедура ГлавноеТабличноеПолеПриАктивацииСтроки(Элемент)
    
    ТекущиеДанныеГлавной = Элемент.ТекущиеДанные;
    Если ТекущиеДанныеГлавной = Неопределено Тогда
        ЭлементыФормы.ПодчиненноеТабличноеПоле.Значение.Очистить();
        Возврат;
    КонецЕсли;
    
    // Структура отбора по ключевому полю связи
    Отбор = Новый Структура;
    Отбор.Вставить("Владелец", ТекущиеДанныеГлавной.Ссылка);
    
    // Копирование отфильтрованных строк из полного хранилища
    ПодчиненнаяТЗОтображение = ХранилищеПодчиненныхДанных.Скопировать(Отбор);
    
    // Привязка полученной таблицы значений к табличному полю
    ЭлементыФормы.ПодчиненноеТабличноеПоле.Значение = ПодчиненнаяТЗОтображение;

КонецПроцедуры

Если подчиненная таблица предназначена исключительно для просмотра, данного подхода вполне достаточно. Если же требуется редактирование данных с сохранением изменений в исходном хранилище, необходимо обращаться к строкам хранилища по их индексам или использовать уникальный идентификатор строки.

Способ 2. Фильтрация с помощью ПостроителяОтчета

Посмотрим на более гибкий способ, который позволяет настраивать сложные условия фильтрации (включая виды сравнения ВСписке, НеРавно, Больше и другие) без написания громоздких условий на встроенном языке.

Для этого используется объект ПостроительОтчета и источник данных ОписаниеИсточникаДанных:


Процедура ОбновитьПодчиненнуюТаблицуСПостроителем(КлючСвязи)

    Построитель = Новый ПостроительОтчета;
    Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(ХранилищеПодчиненныхДанных);
    
    // Настройка отбора
    Отбор = Построитель.Отбор;
    Отбор.Очистить();
    
    ЭлементОтбора = Отбор.Добавить("Владелец");
    ЭлементОтбора.ВидСравнения = ВидСравнения.Равно;
    ЭлементОтбора.Значение = КлючСвязи;
    ЭлементОтбора.Использование = Истина;
    
    // Выгрузка результата в отображаемую таблицу
    ТЗРезультат = Построитель.Результат.Выгрузить();
    
    ЭлементыФормы.ПодчиненноеТабличноеПоле.Значение = ТЗРезультат;

КонецПроцедуры

Способ 3. Использование механизма Запросов

Разберем вариант, когда подчиненная таблица достаточно велика или требуется выполнить сложную группировку и соединение с другими данными. В этом случае исходную таблицу значений передают в параметр запроса.


Процедура ОбновитьПодчиненнуюТаблицуЗапросом(ЗначениеКлюча)

    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   ТЗ.Номенклатура КАК Номенклатура,
        |   ТЗ.Количество КАК Количество,
        |   ТЗ.Цена КАК Цена
        |ИЗ
        |   &ВнешняяТЗ КАК ТЗ
        |ГДЕ
        |   ТЗ.Владелец = &Владелец";
        
    Запрос.УстановитьПараметр("ВнешняяТЗ", ХранилищеПодчиненныхДанных);
    Запрос.УстановитьПараметр("Владелец", ЗначениеКлюча);
    
    ЭлементыФормы.ПодчиненноеТабличноеПоле.Значение = Запрос.Выполнить().Выгрузить();

КонецПроцедуры

Альтернативные архитектурные решения

Если текущая реализация с двумя таблицами значений вызывает сложности в поддержке, проанализируем смежные решения задачи:

  1. Переход на ДеревоЗначений: Вместо двух независимых таблиц создается один объект ДеревоЗначений. Верхний уровень иерархии занимает главная таблица, а вложенные узлы — подчиненная. Пользователь видит подчиненные строки нативно при раскрытии группировок.
  2. Использование временной табличной части: Если добавить на форму или во внешнюю обработку реквизит типа ОбработкаОбъект со встроенными табличными частями, для них будет доступно полноценное свойство ОтборСтрок. Установка отбора в таком случае осуществляется одной строкой кода:
    
    ЭлементыФормы.ПодчиненнаяТабличнаяЧасть.ОтборСтрок.Владелец.Установить(ТекущиеДанные.Ссылка);
    

Таким образом, для реализации связки двух табличных полей типа ТаблицаЗначений рекомендуется использовать перезаполнение отображаемой таблицы через методы Скопировать(), ПостроительОтчета или Запрос, либо пересмотреть архитектуру формы в пользу ДереваЗначений или временных табличных частей.

← На главную