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