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