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

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

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

Различие между объектом ДеревоЗначений и типом ДанныеФормыДерево

Первое, что нам необходимо проанализировать, — это принципиальное различие в типах данных. В обычном приложении мы работали напрямую с объектом ДеревоЗначений. В управляемых формах данные на форме хранятся в специальном формате — ДанныеФормыДерево. Это проекция данных, оптимизированная для передачи между сервером и тонким клиентом.

Рассмотрим ключевое отличие: у объекта ДанныеФормыДерево нет свойства Строки. Именно поэтому попытка обращения ДеревоНастроек.Строки.Очистить() приводит к ошибке. Вместо этого в управляемом интерфейсе используется универсальный метод ПолучитьЭлементы(), который возвращает коллекцию строк текущего уровня иерархии.

Как правильно очистить дерево значений

Для того чтобы полностью очистить дерево на форме, нам не нужно переходить в объектный контекст на стороне сервера. Мы можем сделать это напрямую через реквизит формы. Разберем правильный синтаксис:

Вариант 1. Прямая очистка коллекции элементов

Если нам нужно просто удалить все существующие записи, используем следующий код:


// ИмяРеквизитаДерева — это имя вашего реквизита на форме с типом "Дерево значений"
ЭлементыДерева = ДеревоНастроек.ПолучитьЭлементы();
ЭлементыДерева.Очистить();

Обратите внимание, что метод ПолучитьЭлементы() работает на клиенте, что позволяет выполнять очистку без лишних серверных вызовов, если это не требует сопутствующей логики обработки данных.

Программное добавление колонок в дерево значений

Ситуация с добавлением колонок сложнее. В управляемых формах структура реквизитов жестко определена. Мы не можем просто вызвать Колонки.Добавить(), как в обычном приложении. Процесс разделяется на два глобальных этапа: создание реквизита (данных) и создание элемента формы (визуального поля).

Рассмотрим пошагово, как это реализовать на сервере:

  1. Создание массива новых реквизитов: Мы подготавливаем описание новых колонок.
  2. Вызов метода ИзменитьРеквизиты(): Этот метод физически перестраивает структуру формы.
  3. Создание элементов управления: Привязываем новые колонки к таблице на форме.

Пример программного кода для добавления колонки:


&НаСервере
Процедура ДобавитьКолонкуВДерево(ИмяКолонки, Заголовок)
    
    // Шаг 1: Описываем новый реквизит
    МассивДобавляемыхРеквизитов = Новый Массив;
    ТипКолонки = Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(100));
    НовыйРеквизит = Новый РеквизитФормы(ИмяКолонки, ТипКолонки, "ДеревоНастроек", Заголовок);
    МассивДобавляемыхРеквизитов.Добавить(НовыйРеквизит);
    
    // Шаг 2: Изменяем структуру реквизитов формы
    ЭтаФорма.ИзменитьРеквизиты(МассивДобавляемыхРеквизитов);
    
    // Шаг 3: Добавляем поле на форму в визуальную таблицу
    НовыйЭлемент = Элементы.Добавить("ДеревоНастроек" + ИмяКолонки, Тип("ПолеФормы"), Элементы.ДеревоНастроек);
    НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
    НовыйЭлемент.ПутьКДанным = "ДеревоНастроек." + ИмяКолонки;
    
КонецПроцедуры

Важно помнить, что метод ИзменитьРеквизиты() является крайне ресурсоемким. Постарайтесь формировать массив всех нужных колонок заранее и вызывать этот метод один раз, а не в цикле.

Поиск данных в дереве значений

В типе ДанныеФормыДерево отсутствует привычный метод Найти(). У нас есть два пути решения этой задачи в зависимости от сложности дерева и требований к производительности.

Метод 1. Конвертация в объект ДеревоЗначений

Этот способ удобен, когда нужно выполнить сложный поиск или использовать методы, доступные только серверному объекту. Рассмотрим пример реализации:


&НаСервере
Функция НайтиСтрокуЧерезКонвертацию(ЗначениеПоиска)
    
    // Преобразуем данные формы в реальный объект "ДеревоЗначений"
    ДеревоОбъект = ДанныеФормыВЗначение(ДеревоНастроек, Тип("ДеревоЗначений"));
    
    // Используем стандартный метод поиска
    НайденнаяСтрокаОбъект = ДеревоОбъект.Строки.Найти(ЗначениеПоиска, "ИмяКолонки", Истина);
    
    Если НайденнаяСтрокаОбъект <> Неопределено Тогда
        // Если нашли, можем либо вернуть данные, либо найти идентификатор в ДанныеФормы
        Возврат НайденнаяСтрокаОбъект.ИмяКолонки;
    КонецЕсли;
    
    Возврат Неопределено;
    
КонецФункции

Важно: После манипуляций в ДеревоОбъект, если вы изменили данные, их нужно вернуть обратно на форму методом ЗначениеВДанныеФормы(ДеревоОбъект, ДеревоНастроек);.

Метод 2. Рекурсивный обход коллекции

Для небольших деревьев или когда поиск выполняется по простому условию, эффективнее написать рекурсивную процедуру обхода. Это исключает затраты на сериализацию всей структуры дерева при конвертации.


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

Работа с идентификаторами строк и интерфейсом

Проанализируем еще один важный аспект: управление визуальным состоянием дерева. Каждая строка в ДанныеФормыДерево обладает уникальным числовым идентификатором. Чтобы получить его, используйте метод ПолучитьИдентификатор().

Зачем это нужно? Например, для программного раскрытия узла дерева. Если вы нашли нужную строку и хотите, чтобы пользователь сразу её увидел, используйте метод элемента формы:


Идентификатор = СтрокаДерева.ПолучитьИдентификатор();
Элементы.ДеревоНастроек.Развернуть(Идентификатор, Истина);

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

Оптимизация производительности

Выясним причину возможных замедлений при работе с большими деревьями. Основная нагрузка ложится на передачу данных между сервером и клиентом. Поэтому:

Подводя итог, можно сказать, что работа с деревом значений в управляемом приложении требует четкого понимания контекста выполнения кода и типов данных 1С. Используя связку методов ПолучитьЭлементы(), ИзменитьРеквизиты() и грамотный рекурсивный обход, вы сможете реализовать любую сложную логику управления иерархическими структурами данных.

← На главную