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