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