Почему не отображается дерево значений на управляемой форме и как его заполнить?

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

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

Анализ типовых ошибок при работе с деревом значений

Рассмотрим стандартный сценарий: на форме создан реквизит ДеревоСотрудников с типом ДеревоЗначений, перенесен в элементы формы, а в процедуре ПриСозданииНаСервере выполняется запрос и вызов метода ЗначениеВРеквизитФормы(). В итоге форма открывается, но таблица остается пустой или вовсе не видна. Проанализируем основные причины такого поведения:

  1. Отсутствие колонок у реквизита формы: Метод ЗначениеВРеквизитФормы переносит данные только в те колонки реквизита формы (коллекции ДанныеФормыДерево), которые уже объявлены в структуре реквизита. Если у реквизита формы нет колонок, метод не создает их «на лету» и не вызывает ошибку — он просто игнорирует входящие колонки из объекта ДеревоЗначений.
  2. Отсутствие элементов управления (колонок таблицы): В управляемых формах данные формы отделены от интерфейса. Чтобы пользователь увидел данные, на самой таблице формы должны быть созданы дочерние элементы — поля ввода или надписи, привязанные к колонкам реквизита через свойство ПутьКДанным.
  3. Запрос без секции итогов: Для построения иерархического дерева значений результат запроса должен выгружаться с обходом по группировкам. Метод РезультатЗапроса.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией) сформирует дерево только в том случае, если в тексте запроса присутствует секция ИТОГИ ... ПО .... Без нее будет получен плоский список.
  4. Лишние преобразования данных: Конструкция Дерево = РеквизитФормыВЗначение("ДеревоСотрудников") перед выгрузкой запроса не имеет смысла, так как переменная сразу же перезаписывается результатом выполнения запроса.

Способ 1. Статическая настройка колонок в конфигураторе (рекомендуемый)

Если структура отображаемых данных известна заранее, правильнее всего создать структуру реквизита и визуальные элементы непосредственно в редакторе формы. Рассмотрим этот алгоритм:

  1. В окне реквизитов формы раскроем реквизит ДеревоСотрудников и добавим нужные колонки (например, Группа с типом СправочникСсылка.SSP_ГруппыПользователей и Сотрудник с типом СправочникСсылка.Сотрудники).
  2. Перетащим добавленные колонки внутрь элемента таблицы формы. Первая колонка станет ведущей для отображения иерархических узлов (плюсиков и минусиков).
  3. Напишем корректный запрос с секцией ИТОГИ на сервере и заполним реквизит формы.

Посмотрим на пример серверного кода:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   SSP_ГруппыПользователейСотрудники.Ссылка КАК Группа,
        |   SSP_ГруппыПользователейСотрудники.Сотрудник КАК Сотрудник
        |ИЗ
        |   Справочник.SSP_ГруппыПользователей.Сотрудники КАК SSP_ГруппыПользователейСотрудники
        |ИТОГИ ПО
        |   Группа";

    РезультатЗапроса = Запрос.Выполнить();
    Дерево = РезультатЗапроса.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам);

    ЗначениеВРеквизитФормы(Дерево, "ДеревоСотрудников");

КонецПроцедуры

Способ 2. Полностью программное создание колонок и элементов формы

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

Разберем подробный пример создания реквизитов и колонок в процедуре ПриСозданииНаСервере:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

    // 1. Выполняем запрос с итогами
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   SSP_ГруппыПользователейСотрудники.Ссылка КАК Группа,
        |   SSP_ГруппыПользователейСотрудники.Сотрудник КАК Сотрудник
        |ИЗ
        |   Справочник.SSP_ГруппыПользователей.Сотрудники КАК SSP_ГруппыПользователейСотрудники
        |ИТОГИ ПО
        |   Группа";

    РезультатЗапроса = Запрос.Выполнить();
    Дерево = РезультатЗапроса.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам);

    // 2. Формируем массив новых реквизитов для дерева
    МассивДобавляемыхРеквизитов = Новый Массив;
    
    Для Каждого Колонка Из Дерево.Колонки Цикл
        // Третьим параметром передаем имя родительского реквизита дерева
        РеквизитКолонка = Новый РеквизитФормы(
            Колонка.Имя, 
            Колонка.ТипЗначения, 
            "ДеревоСотрудников", 
            Колонка.Заголовок
        );
        МассивДобавляемыхРеквизитов.Добавить(РеквизитКолонка);
    КонецЦикла;

    // Применяем изменение структуры формы
    ИзменитьРеквизиты(МассивДобавляемыхРеквизитов);

    // 3. Заполняем данные реквизита формы
    ЗначениеВРеквизитФормы(Дерево, "ДеревоСотрудников");

    // 4. Создаем визуальные элементы таблицы
    ТаблицаФормы = Элементы.ДеревоСотрудников;
    ТаблицаФормы.Отображение = ОтображениеТаблицы.Дерево;

    Для Каждого Колонка Из Дерево.Колонки Цикл
        ИмяЭлементаКолонки = "ДеревоСотрудников_" + Колонка.Имя;
        
        ЭлементКолонка = Элементы.Добавить(ИмяЭлементаКолонки, Тип("ПолеФормы"), ТаблицаФормы);
        ЭлементКолонка.Вид = ВидПоляФормы.ПолеВвода;
        ЭлементКолонка.ПутьКДанным = "ДеревоСотрудников." + Колонка.Имя;
        ЭлементКолонка.Заголовок = ?(ЗначениеЗаполнено(Колонка.Заголовок), Колонка.Заголовок, Колонка.Имя);
    КонецЦикла;

КонецПроцедуры

Способ 3. Прямой обход выборки без промежуточного дерева значений

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

Посмотрим на пример заполнения через рекурсивный или двухуровневый обход выборки:


&НаСервере
Процедура ЗаполнитьДеревоНапрямую(ВыборкаГруппы, КоллекцияСтрок)

    Пока ВыборкаГруппы.Следующий() Цикл
        СтрокаГруппы = КоллекцияСтрок.Добавить();
        СтрокаГруппы.Группа = ВыборкаГруппы.Группа;

        ВыборкаДетали = ВыборкаГруппы.Выбрать();
        Пока ВыборкаДетали.Следующий() Цикл
            СтрокаДетали = СтрокаГруппы.Строки.Добавить();
            СтрокаДетали.Сотрудник = ВыборкаДетали.Сотрудник;
        КонецЦикла;
    КонецЦикла;

КонецПроцедуры

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   SSP_ГруппыПользователейСотрудники.Ссылка КАК Группа,
        |   SSP_ГруппыПользователейСотрудники.Сотрудник КАК Сотрудник
        |ИЗ
        |   Справочник.SSP_ГруппыПользователей.Сотрудники КАК SSP_ГруппыПользователейСотрудники
        |ИТОГИ ПО
        |   Группа";

    ВыборкаГруппы = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
    
    // Очищаем существующие строки дерева формы и заполняем новыми
    ДеревоФормы = ДеревоСотрудников.ПолучитьЭлементы();
    ДеревоФормы.Очистить();
    
    ЗаполнитьДеревоНапрямую(ВыборкаГруппы, ДеревоФормы);

КонецПроцедуры

Ограничение типов и редактирование значений

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

  1. На уровне реквизита формы: Задать конкретный тип в свойстве Тип колонки реквизита формы, исключив лишние типы.
  2. На уровне элемента формы: Задать свойство элемента ОграничениеТипа или установить свойство ТолькоПросмотр = Истина, если дерево предназначено исключительно для отображения информации.
← На главную