Как программно развернуть все узлы иерархического справочника или дерева в 1С

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

При работе с иерархическими данными в 1С:Предприятие 8.3 программисты часто сталкиваются с необходимостью реализовать кнопку «Развернуть всё». Стандартное поведение платформы не всегда позволяет сделать это одной командой, особенно если речь идет о динамических списках. В этой статье мы подробно разберем, как эффективно управлять раскрытием узлов дерева на управляемой форме, рассмотрим особенности работы с динамическими данными и проанализируем возможные проблемы производительности.

Метод первый: Использование встроенного метода Развернуть()

Самый правильный и «чистый» с точки зрения архитектуры платформы способ — это использование метода Развернуть() элемента формы. Рассмотрим ситуацию, когда у нас есть таблица, отображающая ДеревоЗначений или ДинамическийСписок с иерархией. Чтобы развернуть конкретный узел и все его дочерние элементы, необходимо вызвать метод с параметром Истина во втором аргументе.

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


&НаКлиенте
Процедура РазвернутьВсеДерево(Команда)
    
    // Получаем все элементы верхнего уровня дерева
    СтрДерева = Элементы.Список.ДанныеСтроки(Элементы.Список.ТекущаяСтрока);
    
    // Если нужно развернуть вообще всё, придется обойти коллекцию
    // Для ДереваЗначений это делается через получение корня
    // Для ДинамическогоСписка — сложнее из-за порционной загрузки
    
    ИдентификаторыОснования = Элементы.Список.ДанныеСтроки(Неопределено); // Пример получения корня
    
    // Основной метод для развертывания текущей ветки и всех вложенных:
    Элементы.Список.Развернуть(Элементы.Список.ТекущаяСтрока, Истина);
    
КонецПроцедуры

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

Метод второй: Переключение режима отображения (Lifehack)

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

Этот способ часто называют «хаком», но он оказывается весьма эффективным, когда обычные методы не срабатывают при повторном нажатии. Разберем по шагам алгоритм, предложенный участниками сообщества:

  1. Запоминаем текущее состояние или используем пометку кнопки.
  2. Переключаем Отображение таблицы из состояния Дерево в Список. Это заставляет платформу сбросить кэш развернутых узлов.
  3. Устанавливаем свойство НачальноеОтображениеДерева в значение РаскрыватьВсеУровни.
  4. Возвращаем Отображение обратно в состояние Дерево.

Пример реализации такой процедуры:


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

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

Особенности динамических списков и производительность

Проанализируем ситуацию с точки зрения производительности. В 1С ДинамическийСписок работает по принципу «ленивой загрузки». Это означает, что данные с сервера подтягиваются только тогда, когда пользователь раскрывает ветку или прокручивает список.

Если мы пытаемся программно заставить ДинамическийСписок развернуть тысячи узлов одновременно:

Рекомендация: Если в вашем справочнике более 500-1000 групп, лучше отказаться от идеи полного развертывания. Вместо этого используйте поиск или разворачивайте дерево только до определенного уровня (например, до второго или третьего).

Исправление работы с COM-объектом WScript.Shell (SendKeys)

Рассмотрим способ, который упоминался как «попытка имитации нажатия клавиш». В среде Windows можно отправить команду нажатия клавиш Ctrl + Shift + Num+ (это стандартное сочетание в 1С для раскрытия дерева). Однако в коде часто допускают ошибки. Если вы решили использовать этот «костыль», то синтаксис должен быть следующим:


ОбъектShell = Новый COMОбъект("Wscript.Shell");
// Символ "+" нужно заключать в фигурные скобки, так как сам по себе он означает Shift
ОбъектShell.SendKeys("^+{ADD}"); // ADD — это код плюса на цифровой клавиатуре

Почему мы не рекомендуем этот метод? Во-первых, он работает только в операционной системе Windows. Во-вторых, фокус ввода должен находиться строго на элементе формы «Список», иначе команда уйдет «в никуда». В-третьих, использование COM-объектов постепенно ограничивается в современных системах безопасности.

Резюме и лучший подход

Подводя итог, можно выделить оптимальную стратегию для программиста 1С:

  1. Для Дерева Значений (которое уже целиком загружено на клиент): используйте цикл по строкам верхнего уровня и метод Развернуть(Идентификатор, Истина).
  2. Для Динамического списка: используйте либо установку свойства НачальноеОтображениеДерева при открытии формы, либо метод с переключением режима отображения, если развертывание нужно выполнять «на лету».
  3. Всегда предупреждайте пользователя или ограничивайте рекурсию, если данных в иерархии слишком много, чтобы избежать критических задержек в работе программы.
← На главную