Как у ДанныеФормыЭлементДерева получить значение владельца (ДанныеФормыДерево)

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

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

Анализ проблемы: почему нет свойства Владелец?

Разберем внутреннюю структуру управляемых форм. Объект ДанныеФормыЭлементДерева спроектирован таким образом, чтобы предоставлять доступ к данным текущей строки и ее непосредственным подчиненным элементам. Метод ПолучитьРодителя() у этого объекта возвращает либо вышестоящий узел (такого же типа), либо значение Неопределено, если строка находится на самом верхнем уровне иерархии. Проанализируем ситуацию: даже если строка является корневой, вызов родителя не вернет вам ссылку на саму коллекцию ДанныеФормыДерево. Это принципиальное отличие от серверного объекта ДеревоЗначений, где работа с коллекциями строк строится несколько иначе.

Попытка избавиться от параметра «Дерево» в функциях обработки строк — это естественное желание упростить код, однако в рамках модели управляемого приложения оно наталкивается на отсутствие прямой ссылки «снизу вверх» от элемента к корню всей структуры.

Разбор типичного кода и его недостатков

Посмотрим на пример кода, который часто встречается в попытках создать «универсальный» механизм получения индексов строки:


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

Проанализируем этот подход. Основная проблема здесь заключается в попытке смешать в одной функции работу с ДанныеФормыДерево (клиентская сущность) и ДеревоЗначений (серверная сущность). Это приводит к загромождению кода проверками ТипЗнч и усложняет отладку. Как отмечают опытные разработчики, такой стиль «заставляет глаза кровоточить», так как он нарушает принцип разделения контекстов.

Решение №1: Явная передача контекста

Самый надежный и производительный способ — всегда передавать объект-владелец (дерево) в качестве параметра функции. Это гарантирует, что функция будет работать предсказуемо и быстро. В типовых конфигурациях (например, на базе БСП) принят именно этот стандарт. Если вам нужно выполнить действие со строкой, функция должна принимать и саму строку, и коллекцию, которой она принадлежит.

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

Решение №2: Использование идентификаторов строк

Вместо того чтобы вычислять «путь» к строке в виде массива индексов (0, 2, 1...), в управляемых формах 1С рекомендуется использовать уникальные идентификаторы. Рассмотрим, как это работает:

  1. У каждого элемента ДанныеФормыЭлементДерева есть метод ПолучитьИдентификатор().
  2. Этот идентификатор является числом, уникальным для данной коллекции в рамках сеанса.
  3. Вместо передачи массива индексов на сервер или в другую процедуру, передавайте идентификатор строки.
  4. Для получения самого объекта строки из дерева используйте метод НайтиПоИдентификатору().

Пример использования идентификатора:


// На клиенте получаем ID строки
ИдентификаторСтроки = Элементы.ДеревоНоменклатуры.ТекущаяСтрока;

// На сервере или в функции обработки находим строку
СтрокаДерева = ДеревоНоменклатуры.НайтиПоИдентификатору(ИдентификаторСтроки);

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

Решение №3: Разделение логики для разных типов данных

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

Создадим отдельные методы для разных типов объектов. Для ДеревоЗначений мы используем свойство Строки и Родитель, а для ДанныеФормыДерево — метод ПолучитьЭлементы() и ПолучитьРодителя().

Рассмотрим пример правильной структуры функции для работы с данными формы:


Функция ПолучитьПутьКСтрокеУправляемойФормы(ТекущийЭлемент, КорневоеДерево)
    Путь = Новый Массив;
    
    Пока ТекущийЭлемент <> Неопределено Цикл
        Родитель = ТекущийЭлемент.ПолучитьРодителя();
        Коллекция = ?(Родитель = Неопределено, КорневоеДерево.ПолучитьЭлементы(), Родитель.ПолучитьЭлементы());
        
        Индекс = Коллекция.Индекс(ТекущийЭлемент);
        Путь.Вставить(0, Индекс);
        
        ТекущийЭлемент = Родитель;
    КонецЦикла;
    
    Возврат Путь;
КонецФункции

Подведем итоги

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

Рекомендации:

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

← На главную