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

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

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

Понимание концепции идентификаторов в управляемых формах

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

Рассмотрим стандартную последовательность действий для добавления вложенного элемента в текущую выделенную строку:

  1. Получаем идентификатор текущей строки из элемента управления на форме.
  2. Находим соответствующую строку в данных (реквизите формы).
  3. Обращаемся к коллекции подчиненных элементов этой строки через метод ПолучитьЭлементы().
  4. Добавляем новую строку в эту коллекцию.

Посмотрим на пример кода, который реализует эту логику:


// 1. Получаем идентификатор выделенной пользователем строки
ИдентификаторТекущейСтроки = Элементы.ДеревоОбъектов.ТекущаяСтрока;

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

Оптимизация массовой загрузки данных в дерево значений

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

В этом случае выясним причину медленной работы и применим более эффективный метод — временную конвертацию реквизита формы в объект «ДеревоЗначений». Разберем этот подход по шагам:

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

Проанализируем пример кода для такой загрузки:


&НаСервере
Процедура ЗагрузитьДанныеВДеревоНаСервере()
    // Конвертируем реквизит в прикладной объект
    ДеревоОбъект = РеквизитФормыВЗначение("ДеревоОбъектов");
    
    // Пример добавления иерархии (аналог работы с обычным деревом)
    НовыйКорень = ДеревоОбъект.Строки.Добавить();
    НовыйКорень.Наименование = "Группа из Excel";
    
    Для Индекс = 1 По 10 Цикл
        НоваяПодчиненная = НовыйКорень.Строки.Добавить();
        НоваяПодчиненная.Наименование = "Элемент №" + Индекс;
    КонецЦикла;
    
    // Возвращаем данные на форму
    ЗначениеВРеквизитФормы(ДеревоОбъект, "ДеревоОбъектов");
КонецПроцедуры

Визуальное отображение добавленных элементов

Часто программисты сталкиваются с тем, что строка программно добавлена, но пользователь её не видит, так как «ветка» дерева свернута. Чтобы сделать работу с интерфейсом удобной, рассмотрим использование метода Развернуть(). Для этого нам снова понадобится идентификатор строки.

Важный нюанс: Метод Развернуть() доступен только на клиенте и работает с элементом формы (таблицей).


// Добавляем строку
НоваяСтрока = РодительскаяСтрока.ПолучитьЭлементы().Добавить();
// Получаем её ID для управления интерфейсом
ИдентификаторНовойСтроки = НоваяСтрока.ПолучитьИдентификатор();

// Разворачиваем родительский узел, чтобы увидеть результат
Элементы.ДеревоОбъектов.Развернуть(РодительскаяСтрока.ПолучитьИдентификатор(), Истина);

// Опционально: устанавливаем фокус на новую строку
Элементы.ДеревоОбъектов.ТекущаяСтрока = ИдентификаторНовойСтроки;

Рекурсивный обход дерева для поиска узла

Иногда требуется добавить подчиненный элемент не в «текущую» строку, а в строку с определенным кодом или наименованием. Для этого разберем классический пример рекурсивного обхода дерева значений. Это универсальный инструмент для работы с любой глубиной вложенности.


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

Типичные ошибки и советы

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

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

← На главную