При работе с иерархическими структурами данных в среде «1С:Предприятие» разработчики часто сталкиваются с необходимостью вывода многоуровневых данных в элемент управления типа «Дерево значений». Одной из классических проблем, особенно при использовании обычных форм, является ситуация, когда верхние уровни иерархии (например, с 1-го по 3-й) отображаются корректно, а более глубокие уровни (4-й уровень и ниже) физически отсутствуют на форме или не раскрываются.
В этой статье мы подробно разберем, почему возникает эта проблема, проанализируем ошибки в алгоритмах ручного построения дерева, рассмотрим методы надежной отладки и покажем, как правильно и быстро решать подобные задачи с помощью платформенных механизмов 1С.
Прежде чем приступать к исправлению кода, нам необходимо четко локализовать проблему. Нам нужно понять: данные вообще не попадают в объект ДеревоЗначений, или же они присутствуют в коллекции в оперативной памяти, но интерфейс табличного поля на форме отказывается их отображать?
Для этого выполним пошаговую проверку с помощью встроенного отладчика 1С:
ЭлементыФормы.Дерево.Значение = ДеревоРезультат;
ДеревоРезультат (или ЭлементыФормы.Дерево.Значение) и нажмем комбинацию клавиш Shift + F9 (Быстрый просмотр).Строки.Строки, затем перейдем на третий уровень и попробуем найти строки четвертого уровня.Если на одном из этапов в отладчике в свойстве Строки мы видим пустое значение или количество элементов равное нулю, то проблема однозначно кроется в алгоритме заполнения дерева значений. Если же в отладчике все строки четвертого уровня заполнены и содержат корректные данные, но на форме «плюсики» для раскрытия веток отсутствуют, проблема заключается в настройках элемента управления «Табличное поле».
Рассмотрим фрагмент кода, представленный автором темы, где дерево строится вручную через последовательную фильтрацию плоской таблицы значений с помощью метода НайтиСтроки():
СтрокаРодитель2 = СтрокаРодитель1.Строки.Добавить();
НайденныеСтроки_ = Таб.НайтиСтроки(Строка2);
Для каждого Строка3 Из НайденныеСтроки_ Цикл
НоваяСтрока = СтрокаРодитель2.Строки.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка3);
КонецЦикла;
Проанализируем этот алгоритм и выявим критические уязвимости, которые приводят к потере веток дерева:
Во-первых, обратим внимание на создание переменной СтрокаРодитель2. Мы добавляем новую строку в коллекцию подчиненных строк предыдущего уровня, но забываем заполнить ее ключевые свойства. Для корректного отображения иерархии строка-родитель обязательно должна содержать данные в той колонке, по которой в табличном поле установлено отображение иерархии. Если ячейка пуста, платформа может счесть строку пустой и визуально скрыть кнопку раскрытия ветки («плюсик»). Нам обязательно нужно вызывать метод заполнения:
СтрокаРодитель2 = СтрокаРодитель1.Строки.Добавить();
ЗаполнитьЗначенияСвойств(СтрокаРодитель2, Строка2); // Заполняем родительскую строку данными!
Во-вторых, критическая ошибка часто кроется в формировании структуры отбора для метода НайтиСтроки(). В коде автора поиск подчиненных строк осуществляется по структуре Строка2, которая содержит только колонки группировки третьего уровня:
НайденныеСтроки_ = Таб.НайтиСтроки(Строка2);
Если значения колонок на третьем уровне не являются абсолютно уникальными в рамках всей таблицы (например, в разных ветках дерева встречаются одинаковые названия складов, номенклатурных групп или статусов), метод НайтиСтроки() вернет избыточные данные, принадлежащие другим веткам. И наоборот, если структура отбора сформирована некорректно или содержит несовпадающие типы данных, метод вернет пустой массив строк. В результате четвертый уровень дерева останется пустым.
Для гарантированно точного поиска структура отбора на каждом последующем уровне вложенности должна быть составной и включать в себя ключевые поля всех предыдущих родительских уровней.
Если в процессе стандартной отладки вам неудобно кликать по вложенным коллекциям строк, существует отличный платформенный инструмент быстрого визуального анализа дерева значений. На точке останова в окне вычисления выражений (Shift + F9) введите следующую команду:
ДеревоРезультат.ВыбратьСтроку()
Этот метод открывает стандартное модальное окно платформы 1С, предназначенное для интерактивного просмотра структуры дерева. В этом окне выводятся абсолютно все колонки и строки. Если в данном окне вы можете раскрыть третий уровень и увидеть четвертый уровень данных, значит, программное построение работает идеально, а проблема локализована в интерфейсе формы.
Если данные в дереве точно есть, но на обычных формах четвертый уровень не отображается, проверим настройки элемента управления ТабличноеПоле:
Истина. Обычно это первая колонка дерева (например, «Наименование» или «Группа»).ЭлементыФормы.Дерево.Значение = ДеревоРезультат;, структура колонок табличного поля на форме должна полностью соответствовать структуре колонок объекта ДеревоЗначений. Если вы динамически изменили состав колонок дерева в коде, обязательно вызовите метод принудительного обновления колонок на форме:
ЭлементыФормы.Дерево.СоздатьКолонки();
Важно помнить: метод СоздатьКолонки() сбрасывает все визуальные настройки ширины, видимости и оформления колонок, которые вы настраивали в конфигураторе вручную. Поэтому предпочтительнее один раз жестко настроить колонки на форме и в коде строго следовать этой структуре.
Написание многоуровневых вложенных циклов с постоянной фильтрацией таблиц через НайтиСтроки() — это устаревший, ресурсоемкий и крайне подверженный ошибкам путь разработки. Платформа 1С предоставляет мощный встроенный механизм для автоматического формирования иерархических деревьев любой глубины с помощью запросов с предложением ИТОГИ.
Давайте рассмотрим, как можно изящно и в одну строчку кода построить правильное четырехъярусное дерево значений напрямую из базы данных или из временной таблицы:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Продажи.Организация КАК Организация,
| Продажи.Контрагент КАК Контрагент,
| Продажи.Договор КАК Договор,
| Продажи.Номенклатура КАК Номенклатура,
| Продажи.СуммаОборот КАК Сумма
|ИЗ
| РегистрНакопления.Продажи.Обороты КАК Продажи
|
|ИТОГИ
| СУММА(Сумма)
|ПО
| Организация,
| Контрагент,
| Договор,
| Номенклатура";
РезультатЗапроса = Запрос.Выполнить();
// Выгружаем результат в дерево значений с обходом по группировкам
ДеревоРезультат = РезультатЗапроса.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам);
// Привязываем готовое дерево к элементу формы
ЭлементыФормы.Дерево.Значение = ДеревоРезультат;
ЭлементыФормы.Дерево.СоздатьКолонки();
Разберем подробнее, почему этот подход решает все проблемы с отображением уровней:
ИТОГИ ПО вашего запроса. Никаких новых вложенных циклов писать не придется.Используя данный подход, вы навсегда избавитесь от проблем с нераскрывающимися ветками и неверно сформированными строками в иерархических таблицах 1С.