Разработка и Конфигурация · 11 мин
Как развернуть дерево на форме в 1С
Как программно развернуть дерево значений на управляемой форме 1С: метод Развернуть, обход строк, разворачивание до уровня и типичные ошибки разработчика.
Дерево значений на управляемой форме 1С по умолчанию отображается свёрнутым: пользователь видит только корневые строки, а вложенные уровни раскрывает вручную. Для иерархических справочников, деревьев группировок отчётов и многоуровневых подборов это неудобно — логично развернуть дерево программно при открытии формы или после обновления данных.
Разворачивание выполняется методом Развернуть() элемента формы типа «Таблица», связанного с деревом значений. Ключевой нюанс: метод работает с идентификаторами строк коллекции ДеревоЗначений.ПолучитьЭлементы(), а не с самими строками дерева. Путаница между строкой дерева и её идентификатором — самая частая причина ошибок.
Ниже разобраны рабочие сценарии: разворачивание всего дерева целиком, раскрытие до заданного уровня, разворачивание одной ветки, а также восстановление состояния после перезаполнения дерева. Все примеры применимы к управляемым формам в режиме тонкого и веб-клиента.
Как устроено дерево значений на форме
На управляемой форме иерархические данные хранятся в реквизите формы типа «ДеревоЗначений». Визуально его отображает элемент формы «Таблица», у которого свойство «Отображение» установлено в значение «Дерево». Именно через этот элемент выполняются все операции разворачивания и сворачивания.
Важно различать два объекта. Реквизит ДеревоЗначений — это данные: коллекция строк с вложенными строками. Элемент формы Элементы.Дерево — это представление, которое управляет тем, какие строки раскрыты. Методы Развернуть() и Свернуть() есть только у элемента формы.
Каждая строка дерева на форме имеет уникальный идентификатор, который возвращает метод ПолучитьИдентификатор() строки дерева. Именно этот числовой идентификатор передаётся в метод Развернуть(). Передать туда саму строку или её индекс нельзя — будет ошибка.
Разворачивание всего дерева целиком
Базовый сценарий — раскрыть все уровни сразу. Для этого обходятся строки верхнего уровня, и для каждой вызывается Развернуть() со вторым параметром Истина, который означает «включая все подчинённые строки».
&НаКлиенте
Процедура РазвернутьДерево(Команда)
ЭлементыДерева = Дерево.ПолучитьЭлементы();
Для Каждого СтрокаДерева Из ЭлементыДерева Цикл
Элементы.Дерево.Развернуть(
СтрокаДерева.ПолучитьИдентификатор(), Истина);
КонецЦикла;
КонецПроцедуры
Обратите внимание: процедура выполняется &НаКлиенте, потому что метод Развернуть() доступен только на клиенте — он управляет визуальным отображением. Если дерево заполняется на сервере, разворачивать его нужно после возврата управления в клиентский контекст.
- 1Убедитесь, что у элемента формы «Таблица» свойство Отображение = Дерево
- 2Получите строки верхнего уровня: Дерево.ПолучитьЭлементы()
- 3В цикле для каждой строки вызовите Элементы.Дерево.Развернуть(Строка.ПолучитьИдентификатор(), Истина)
- 4Выполняйте код в контексте &НаКлиенте — на сервере метод недоступен
- 5Проверьте результат: все уровни иерархии раскрыты без кликов пользователя
Разворачивание до нужного уровня
Полное разворачивание не всегда удобно: при глубокой иерархии пользователь получает «простыню» из сотен строк. Практичнее раскрыть только первый или второй уровень, чтобы был виден общий каркас, а детали открывались по требованию.
Для раскрытия одного уровня вызовите Развернуть() без второго параметра (по умолчанию он равен Ложь) — строка раскроется, но её подчинённые останутся свёрнутыми. Для раскрытия до заданной глубины используйте рекурсивный обход с контролем уровня:
&НаКлиенте
Процедура РазвернутьДоУровня(Строки, ТекущийУровень, МаксУровень)
Если ТекущийУровень > МаксУровень Тогда
Возврат;
КонецЕсли;
Для Каждого СтрокаДерева Из Строки Цикл
Элементы.Дерево.Развернуть(
СтрокаДерева.ПолучитьИдентификатор());
РазвернутьДоУровня(
СтрокаДерева.ПолучитьЭлементы(),
ТекущийУровень + 1, МаксУровень);
КонецЦикла;
КонецПроцедуры
Вызов верхнего уровня выглядит так: РазвернутьДоУровня(Дерево.ПолучитьЭлементы(), 1, 2) — раскроются первый и второй уровни. Учтите, что при большом числе строк рекурсивный обход с разворачиванием каждой строки вызывает заметную перерисовку формы; для очень больших деревьев лучше ограничивать глубину.
Варианты разворачивания
Раскрывает всё дерево. Подходит для небольших иерархий; на больших данных замедляет отрисовку формы.
Раскрывает один уровень конкретной строки. Используется для поэтапного раскрытия и точечной навигации.
Компромисс: видна структура, но форма не перегружена. Требует собственной процедуры обхода.
Разворачивание при открытии формы и после обновления
Типичная задача — развернуть дерево сразу при открытии формы. Прямой вызов в обработчике ПриОткрытии часто не срабатывает: элемент формы ещё не готов, и разворачивание «съедается» первичной отрисовкой. Надёжный приём — использовать ПодключитьОбработчикОжидания с минимальной задержкой однократно:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
ПодключитьОбработчикОжидания("РазвернутьДеревоПослеОткрытия", 0.1, Истина);
КонецПроцедуры
&НаКлиенте
Процедура РазвернутьДеревоПослеОткрытия()
Для Каждого СтрокаДерева Из Дерево.ПолучитьЭлементы() Цикл
Элементы.Дерево.Развернуть(
СтрокаДерева.ПолучитьИдентификатор(), Истина);
КонецЦикла;
КонецПроцедуры
Вторая типичная ситуация — дерево перезаполняется на сервере (например, по кнопке «Обновить»). После перезаполнения все идентификаторы строк меняются, а состояние развёрнутости теряется. Поэтому разворачивание нужно повторять после каждого обновления данных, в клиентской процедуре, следующей за серверным вызовом.
Если требуется не просто развернуть всё заново, а восстановить прежнее состояние, перед перезаполнением сохраните ключи раскрытых строк (например, значения ключевого поля) в массив или соответствие, а после заполнения обойдите новое дерево и разверните строки, чьи ключи есть в сохранённом списке.
Разворачивание одной ветки и позиционирование на строке
Иногда нужно раскрыть не всё дерево, а путь к конкретной строке — например, при переходе из другой формы к найденному элементу. Алгоритм: найти строку в дереве, подняться по родителям и развернуть каждого из них, затем установить текущую строку.
&НаКлиенте
Процедура ПоказатьСтрокуВДереве(НайденнаяСтрока)
Родитель = НайденнаяСтрока.ПолучитьРодителя();
Пока Родитель <> Неопределено Цикл
Элементы.Дерево.Развернуть(Родитель.ПолучитьИдентификатор());
Родитель = Родитель.ПолучитьРодителя();
КонецЦикла;
Элементы.Дерево.ТекущаяСтрока =
НайденнаяСтрока.ПолучитьИдентификатор();
КонецПроцедуры
Поиск самой строки выполняется рекурсивным обходом дерева по значению ключевого поля (ссылки, кода). Установка ТекущаяСтрока дополнительно прокручивает таблицу к нужной позиции, поэтому связка «развернуть родителей + установить текущую строку» даёт готовый механизм навигации по дереву.
Если дерево строится из иерархического справочника, удобно хранить в отдельной колонке ссылку на элемент. Это упрощает и поиск строки для разворачивания, и сохранение состояния при перезаполнении — ссылка является стабильным ключом.
Типичные ошибки и ограничения
Большинство проблем при разворачивании дерева связано с неправильным контекстом выполнения или неверными параметрами метода. Ниже собраны ошибки, которые встречаются чаще всего.
Отдельно стоит помнить про производительность: разворачивание дерева из нескольких тысяч строк заставляет клиентское приложение отрисовать все строки сразу. На слабых клиентах и в веб-клиенте это может занимать секунды. В таких случаях разворачивайте только первый уровень либо пересмотрите интерфейс в пользу отображения «Список» с иерархией.
Как проверить результат
Свойство Отображение = Дерево, видны значки раскрытия у строк
Установлен Список или Иерархический список — вложенные строки не показываются
После выполнения кода все уровни раскрыты без действий пользователя
Дерево остаётся свёрнутым — проверьте контекст выполнения и идентификаторы
Дерево перезаполняется и снова разворачивается
После обновления всё свёрнуто — разворачивание не вызывается повторно
FAQ: частые вопросы о разворачивании дерева в 1С
Как свернуть дерево обратно программно?
Используйте метод Свернуть(ИдентификаторСтроки) элемента формы для каждой строки верхнего уровня. В отличие от Развернуть(), параметра «с подчинёнными» нет: сворачивание родителя автоматически скрывает все вложенные уровни.
Работает ли Развернуть() в обычных формах?
В обычных формах используется элемент «ТабличноеПоле» с аналогичным методом Развернуть(Строка, СПодчиненными), но в него передаётся сама строка дерева значений, а не идентификатор. Принцип обхода строк верхнего уровня тот же.
Почему дерево не разворачивается в ПриОткрытии?
В момент выполнения ПриОткрытии элемент формы ещё не завершил первичную отрисовку, и команда разворачивания теряется. Вынесите вызов в однократный обработчик ожидания с задержкой 0,1–0,5 секунды через ПодключитьОбработчикОжидания.
Как развернуть только одну конкретную ветку?
Найдите нужную строку обходом дерева по ключевому полю, затем поднимитесь через ПолучитьРодителя() до корня, разворачивая каждого родителя методом Развернуть() без второго параметра. Саму ветку при необходимости раскройте с параметром Истина.
Можно ли запомнить, какие ветки раскрыл пользователь?
Да. Перед перезаполнением дерева сохраните ключи (ссылки, коды) раскрытых строк — проверить состояние можно методом Развернут(ИдентификаторСтроки). После заполнения пройдите по новому дереву и разверните строки с совпадающими ключами.
Дерево из тысяч строк разворачивается очень медленно. Что делать?
Полное разворачивание большого дерева всегда дорогое из-за отрисовки. Ограничьтесь первым–вторым уровнем, разворачивайте ветки по требованию или замените отображение на иерархический список — он показывает вложенность порциями и работает быстрее.
Что важно запомнить
Дерево разворачивается методом Элементы.Дерево.Развернуть(ИдентификаторСтроки, Истина) только на клиенте. Для полного раскрытия обойдите строки верхнего уровня; для раскрытия до уровня используйте рекурсию. При открытии формы вызывайте код через обработчик ожидания, а после каждого перезаполнения дерева разворачивайте его заново, сохраняя состояние по ключам строк.