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