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

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

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

Проблема типов данных: ДанныеФормыЭлементДерева против СтрокаДереваЗначений

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

Однако в управляемой форме данные дерева хранятся в реквизите с типом ДанныеФормыДерево, а текущая строка, с которой мы взаимодействуем на клиенте, имеет тип ДанныеФормыЭлементДерева. У этого типа метода Уровень() не существует. Именно поэтому прямой вызов функции на клиенте приведет к ошибке. Рассмотрим основные пути обхода этого ограничения.

Способ 1. Программное вычисление уровня на клиенте (через цикл)

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

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


&НаКлиенте
Функция ПолучитьУровеньДереваТекущейСтрокиКлиент(ТекущаяСтрока)
    
    УровеньТекущейСтроки = 0;
    
    // Получаем родителя текущей строки
    РодительТекущейСтроки = ТекущаяСтрока.ПолучитьРодителя();
    
    // Выполняем цикл, пока не дойдем до самого верхнего уровня (где родитель — Неопределено)
    Пока РодительТекущейСтроки <> Неопределено Цикл
        
        УровеньТекущейСтроки = УровеньТекущейСтроки + 1;  
        // Переходим к родителю следующего уровня
        РодительТекущейСтроки = РодительТекущейСтроки.ПолучитьРодителя();
        
    КонецЦикла;
    
    Возврат УровеньТекущейСтроки;
    
КонецФункции

В обработчике события «Выбор» это будет выглядеть следующим образом:


&НаКлиенте
Процедура ДеревоВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
    
    // Получаем объект данных строки по её идентификатору
    ТекущиеДанные = Элементы.Дерево.ДанныеСтроки(ВыбраннаяСтрока);
    
    Если ТекущиеДанные <> Неопределено Тогда
        Уровень = ПолучитьУровеньДереваТекущейСтрокиКлиент(ТекущиеДанные);
        Сообщить("Текущий уровень строки: " + Уровень);
    КонецЕсли;
    
КонецПроцедуры

Способ 2. Использование скрытой колонки (Оптимальный для производительности)

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

Разберем этот метод по шагам:

  1. Добавление реквизита: В реквизит формы типа ДанныеФормыДерево добавьте новую колонку (например, УровеньСтроки) с типом Число.
  2. Заполнение на сервере: При заполнении дерева на сервере (например, в ПриСозданииНаСервере или специальной процедуре загрузки), рассчитайте уровень один раз для каждой строки, используя стандартный метод Уровень() объекта СтрокаДереваЗначений.
  3. Доступ на клиенте: Теперь на клиенте вам не нужно ничего вычислять. Вы просто обращаетесь к значению колонки: ТекущиеДанные.УровеньСтроки.

Преимущество: Этот метод мгновенно отрабатывает в любой ситуации и идеально подходит, если вам нужно использовать уровень для условного оформления (например, выделять жирным шрифтом только строки 1-го уровня).

Способ 3. Обращение к серверу через идентификатор

Иногда уровень строки нужен для выполнения сложной бизнес-логики на сервере. В этом случае не стоит считать уровень на клиенте и передавать его параметром. Правильнее передать идентификатор строки.

Важно помнить: параметр ВыбраннаяСтрока в обработчике — это идентификатор (число), а не индекс. Рассмотрим, как найти строку на сервере:


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

Важное примечание: Использование ПолучитьОбъект() создает копию строки в памяти, поэтому для массовых операций лучше использовать тот же цикл по ПолучитьРодителя(), но уже на серверной стороне, чтобы избежать лишних затрат ресурсов.

Различие между Идентификатором и Индексом

Проанализируем важный технический момент, затронутый в обсуждении. Многие начинающие разработчики путают идентификатор строки дерева и её индекс.

Идентификатор:

Индекс:

Поэтому в обработчиках событий всегда следует использовать метод Элементы.ИмяДерева.ДанныеСтроки(Идентификатор) для получения доступа к полям строки.

Резюме

Мы рассмотрели три способа определения уровня строки дерева значений. Для простых задач идеально подходит Способ 1 с циклом Пока. Если же дерево активно используется в интерфейсе (например, для раскраски строк), лучше выбрать Способ 2 со скрытой колонкой. Это обеспечит максимальную отзывчивость программы и упростит поддержку кода в будущем.

← На главную