Как программно отметить все флажки в дереве значений 1С и не допустить сворачивания узлов

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

Работа с иерархическими структурами в управляемых формах 1С:Предприятие 8.3 часто преподносит сюрпризы начинающим разработчикам. Одной из типичных задач является реализация кнопки «Отметить все» для дерева значений, где каждая строка имеет флажок (поле типа Булево). Однако при использовании стандартных методов работы с объектами на сервере программисты сталкиваются с тем, что дерево «схлопывается» — все развернутые пользователем узлы автоматически сворачиваются до верхнего уровня. Разберем, почему это происходит и как правильно реализовать задачу, сохранив удобство интерфейса.

Почему дерево значений сворачивается?

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

  1. Конвертация данных формы в объект ДеревоЗначений через РеквизитФормыВЗначение.
  2. Обход строк объекта и установка флажка в значение Истина.
  3. Обратная конвертация объекта в данные формы через ЗначениеВРеквизитФормы.

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

Решение №1: Рекурсивный обход на клиенте (рекомендуемое)

Самый эффективный способ избежать сворачивания строк — это модификация данных непосредственно в контексте ДанныеФормыДерево без обращения к серверному объекту ДеревоЗначений. Если мы меняем значения свойств существующих строк на клиенте, идентификаторы строк сохраняются, и визуальное состояние таблицы не меняется.

Рассмотрим пример кода, который реализует рекурсивную установку флажков. Допустим, наше дерево в реквизитах формы называется ДеревоРабот, а колонка с флажком — Отметка.


&НаКлиенте
Процедура ОтметитьВсе(Команда)
    // Передаем корень дерева в рекурсивную функцию
    УстановитьФлажкиРекурсивно(ДеревоРабот);
КонецПроцедуры

&НаКлиенте
Процедура УстановитьФлажкиРекурсивно(ЭлементКоллекции)
    // Получаем дочерние элементы текущего узла
    Строки = ЭлементКоллекции.ПолучитьЭлементы();
    
    Для Каждого СтрокаДерева Из Строки Цикл
        // Устанавливаем флажок
        СтрокаДерева.Отметка = Истина;
        
        // Рекурсивно заходим вглубь иерархии
        УстановитьФлажкиРекурсивно(СтрокаДерева);
    КонецЦикла;
КонецПроцедуры

В данном примере метод ПолучитьЭлементы() позволяет нам перемещаться по уровням иерархии ДанныеФормыДерево. Этот подход работает быстро, если дерево содержит до нескольких тысяч строк, и абсолютно не влияет на состояние развернутых узлов.

Решение №2: Использование серверного обхода без конвертации в объект

Если логика установки флажков требует обращения к серверным данным (например, нужно проверять остатки на складах или права доступа для каждой строки), можно выполнить аналогичный обход на сервере, но работать нужно именно с типом ДанныеФормыДерево, не вызывая РеквизитФормыВЗначение.

Выясним, как это выглядит в коде:


&НаСервере
Процедура ОтметитьВсеНаСервере()
    ОбходДанныхФормы(Объект.ТаблицаАнализа);
КонецПроцедуры

&НаСервере
Процедура ОбходДанныхФормы(Коллекция)
    Для Каждого Строка Из Коллекция.ПолучитьЭлементы() Цикл
        Строка.Отм = Истина;
        // Рекурсия по дочерним элементам ДанныеФормыДерево
        ОбходДанныхФормы(Строка);
    КонецЦикла;
КонецПроцедуры

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

Решение №3: Программное восстановление состояния (если серверный объект необходим)

В некоторых сложных случаях разработчику все же приходится использовать РеквизитФормыВЗначение (например, когда нужно задействовать специфические методы объекта ДеревоЗначений, такие как Скопировать(), ВыбратьУзлы() или сложные сортировки). В этой ситуации придется вручную запоминать и восстанавливать состояние строк.

Проанализируем алгоритм реализации этого метода:

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

Пример реализации восстановления состояния:


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

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

Дополнительные рекомендации по работе с флажками

При реализации иерархических флажков пользователи часто ожидают «умного» поведения. Рассмотрим два полезных улучшения:

1. Зависимость «Родитель — Потомок». Логично, что при установке флажка у родительского узла, должны отметиться все подчиненные элементы. И наоборот: если мы снимаем флажок у родителя, все вложенные элементы также должны его лишиться. Это реализуется через событие ПриИзменении поля флажка в таблице.

2. Третье состояние флажка. В профессиональных интерфейсах, если у родителя выбрана только часть дочерних элементов, флажок отображается «закрашенным» (неопределенное состояние). В 1С это реализуется через подмену стандартного флажка колонкой с картинкой. Вместо типа Булево используется Число со значениями: 0 — не выбрано, 1 — выбрано, 2 — выбрано частично. В свойство ПутьКДаннымКартинки устанавливается путь к этому числовому полю, а в саму коллекцию картинок загружаются иконки различных состояний флажка.

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

← На главную