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