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

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

При переходе с обычных форм на управляемые многие разработчики сталкиваются с классической ошибкой: «Ошибка передачи данных между клиентом и сервером. Отсутствует отображение для типа 'СтрокаДереваЗначений'». Это происходит из-за фундаментального различия в архитектуре: в управляемом приложении объекты ДеревоЗначений и СтрокаДереваЗначений существуют только на сервере, а на форме мы работаем с их проекцией — типом ДанныеФормыДерево.

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

Разбираем причину ошибки типизации

Рассмотрим ситуацию: вы пытаетесь передать строку дерева из серверной процедуры на клиент или сохранить её в переменной модуля. В обычных формах (ОФ) ТекущаяСтрока была полноценным объектом. В управляемых формах (УФ) передача объекта СтрокаДереваЗначений между контекстами невозможна. На клиенте строка дерева идентифицируется только числом — идентификатором.

Для решения этой проблемы мы должны использовать методы платформы, предназначенные для работы с ДанныеФормыДерево. Основной метод, который заменяет привычное свойство Строки, — это метод ПолучитьЭлементы().

Способ 1. Прямое добавление строк в реквизит формы

Если нам нужно добавить строку в корень дерева или в конкретный узел прямо на сервере, мы используем объект реквизита формы. Проанализируем простейший пример построения двух уровней иерархии:


&НаСервере
Процедура ДобавитьСтрокуВДеревоНаСервере()
    
    // Добавляем строку в корень дерева
    // ДеревоОбъектов — это имя вашего реквизита формы с типом ДанныеФормыДерево
    НоваяСтрокаРодитель = ДеревоОбъектов.ПолучитьЭлементы().Добавить();
    НоваяСтрокаРодитель.Наименование = "Группа документов";
    
    // Добавляем подчиненную строку (ребенок)
    // Мы вызываем ПолучитьЭлементы() уже у объекта конкретной строки
    ПодчиненнаяСтрока = НоваяСтрокаРодитель.ПолучитьЭлементы().Добавить();
    ПодчиненнаяСтрока.Наименование = "Накладная №1";
    ПодчиненнаяСтрока.Дата = ТекущаяДата();
    
КонецПроцедуры

Важный момент: НоваяСтрокаРодитель в данном контексте имеет тип ДанныеФормыЭлементДерева. Этот объект «живет» на сервере в рамках одного вызова и автоматически синхронизируется с формой. Нам не нужно вызывать ЗначениеВРеквизитФормы, если мы работаем напрямую с реквизитом.

Способ 2. Рекурсивное построение иерархии (на примере документов)

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


&НаСервере
Перем ТекСтрока; // Переменная модуля для хранения текущего контекста (в пределах одного вызова)

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

Обратите внимание на использование Перем в начале модуля. Это позволяет «протаскивать» состояние объекта строки сквозь глубокие рекурсивные вызовы, не теряя связь с иерархией. Однако помните, что такая переменная очистится, как только управление вернется на клиент.

Способ 3. Работа через промежуточный объект ДеревоЗначений

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

Рассмотрим по шагам этот процесс:

  1. Создаем объект ДеревоЗначений на сервере (для отладки запросов удобно использовать Консоль запросов для управляемых форм — для этого подойдёт универсальная консоль запросов и СКД для управляемых форм).
  2. Заполняем его данными (запросом или перебором).
  3. Конвертируем результат в реквизит формы одной командой.

&НаСервере
Процедура ЗаполнитьДеревоЧерезПреобразование()
    
    // 1. Преобразуем реквизит формы в объект Дерево Значений, чтобы получить структуру колонок
    ОбъектДерево = РеквизитФормыВЗначение("ДеревоДокументов", Тип("ДеревоЗначений"));
    
    // 2. Очищаем строки (если нужно)
    ОбъектДерево.Строки.Очистить();
    
    // 3. Добавляем данные, используя стандартное свойство .Строки
    НоваяСтр = ОбъектДерево.Строки.Добавить();
    НоваяСтр.Наименование = "Корневой узел";
    
    ПодчиненнаяСтр = НоваяСтр.Строки.Добавить();
    ПодчиненнаяСтр.Наименование = "Подчиненный узел";
    
    // 4. Загружаем объект обратно в реквизит формы
    ЗначениеВРеквизитФормы(ОбъектДерево, "ДеревоДокументов");
    
КонецПроцедуры

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

Оптимизация и работа с идентификаторами

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


// Код на клиенте
ИдентификаторСтроки = Элементы.ДеревоДокументов.ТекущаяСтрока;
ДобавитьНаСервере(ИдентификаторСтроки);

// Код на сервере
&НаСервере
Процедура ДобавитьНаСервере(ИдентификаторСтроки)
    
    // Находим строку в реквизите формы по её ID
    РодительскаяСтрока = ДеревоДокументов.НайтиПоИдентификатору(ИдентификаторСтроки);
    
    Если РодительскаяСтрока <> Неопределено Тогда
        НоваяСтрока = РодительскаяСтрока.ПолучитьЭлементы().Добавить();
        НоваяСтрока.Текст = "Новая подстрока";
    КонецЕсли;
    
КонецПроцедуры

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

Основные рекомендации

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

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

← На главную