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

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

Работа с деревьями значений на управляемых формах 1С часто вызывает затруднения у начинающих разработчиков. В отличие от обычных форм, здесь существует четкое разделение между данными, которые живут на сервере в виде прикладных объектов (ДеревоЗначений), и данными формы (ДанныеФормыДерево). Рассмотрим подробно, как правильно загрузить результат запроса в дерево на форме, разберем причины типовых ошибок и выясним, как настроить колонки для корректной работы.

Постановка задачи

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

Разбор основной ошибки при вызове ЗначениеВРеквизитФормы

Многие разработчики сталкиваются с ошибкой: "Ошибка при вызове метода контекста (ЗначениеВРеквизитФормы): Недопустимое значение параметра (параметр номер '2')". Проанализируем ситуацию: эта ошибка возникает, когда система не может найти реквизит формы по указанному строковому имени или когда структура прикладного объекта не совпадает со структурой реквизита.

Рассмотрим важные нюансы работы этого метода:

  1. Путь к реквизиту: Если ваше дерево является основным реквизитом формы (находится на верхнем уровне), вы указываете его имя, например, "ДеревоКритериев". Если же оно вложено в другой объект (например, является частью табличной части или реквизита Объект), путь должен быть полным: "Объект.ДеревоКритериев".
  2. Совпадение колонок: Объект ДеревоЗначений, который вы передаете первым параметром, должен иметь точно такой же набор колонок и типов данных, что и реквизит формы. Если в запросе вы получили поле Сотрудник, а в реквизите формы такой колонки нет — возникнет ошибка.

Важность свойства «Использовать всегда»

Одной из самых неочевидных причин ошибки "Несоответствие типов" при заполнении данных формы является механизм оптимизации платформы 1С. Разберем по шагам, что происходит:

Когда вы создаете колонки в дереве на форме, но не выводите их в элементы (делаете невидимыми), платформа может "выкинуть" эти данные из состава ДанныеФормыДерево на стороне клиента для экономии памяти. При попытке выполнить ЗначениеВРеквизитФормы сервер обнаруживает, что в прикладном объекте 10 колонок, а в реквизите формы (с точки зрения текущего контекста) их меньше. Это приводит к конфликту.

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

Способ 1: Автоматическая загрузка через ИТОГИ запроса

Это наиболее эффективный и "чистый" способ формирования иерархии. Проанализируем пример кода, где дерево строится самой платформой на основе итогов запроса:


&НаСервере
Процедура ЗагрузитьДеревоИзЗапросаНаСервере()
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   КадроваяИстория.Сотрудник КАК Сотрудник,
        |   Критерии.Должность КАК Должность,
        |   Критерии.Критерий КАК Критерий,
        |   Критерии.КБалл КАК КБалл
        |ИЗ
        |   РегистрСведений.С05_КритерииОценки КАК Критерии
        |ИТОГИ 
        |   МАКСИМУМ(КБалл)
        |ПО
        |   Сотрудник,
        |   Должность";
    
    // Выполняем запрос и выгружаем результат сразу в дерево значений
    // Параметр ОбходРезультатаЗапроса.ПоГруппировкамСИерархией создаст узлы дерева
    РезультатЗапроса = Запрос.Выполнить();
    ДеревоОбъект = РезультатЗапроса.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);
    
    // Копируем данные из прикладного объекта в реквизит формы
    ЗначениеВРеквизитФормы(ДеревоОбъект, "ДеревоКритериев");
    
КонецПроцедуры

Способ 2: Ручное заполнение дерева значений (перебор выборки)

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


&НаСервере
Процедура ЗаполнитьДеревоВручную()
    
    // 1. Получаем объект ДеревоЗначений из реквизита формы
    тДерево = РеквизитФормыВЗначение("ДеревоКритериев");
    тДерево.Строки.Очистить(); // Очищаем старые данные
    
    Запрос = Новый Запрос("ВЫБРАТЬ ... УПОРЯДОЧИТЬ ПО Сотрудник");
    Выборка = Запрос.Выполнить().Выбрать();
    
    ТекущийСотрудник = Неопределено;
    РодительскаяСтрока = Неопределено;
    
    Пока Выборка.Следующий() Цикл
        
        // Создаем новый уровень иерархии при смене сотрудника
        Если ТекущийСотрудник <> Выборка.Сотрудник Тогда
            РодительскаяСтрока = тДерево.Строки.Добавить();
            РодительскаяСтрока.Сотрудник = Выборка.Sotrudnik;
            РодительскаяСтрока.ЭтоГруппа = Истина;
            ТекущийСотрудник = Выборка.Сотрудник;
        КонецЕсли;
        
        // Добавляем подчиненную строку (критерий)
        НоваяСтрока = РодительскаяСтрока.Строки.Добавить();
        НоваяСтрока.Критерий = Выборка.Критерий;
        НоваяСтрока.КбаллФакт = 0;
        НоваяСтрока.ЭтоГруппа = Ложь;
        
    КонецЦикла;
    
    // 2. Возвращаем заполненный объект в реквизит формы
    ЗначениеВРеквизитФормы(тДерево, "ДеревоКритериев");
    
КонецПроцедуры

Типичные ошибки при работе с типами данных

Выясним причину ещё одной проблемы: несоответствие типов в колонках. Если в реквизите формы колонка имеет тип Число(10, 0), а запрос возвращает результат вычислений, который платформа интерпретирует как Число(15, 2), метод ЗначениеВРеквизитФормы может выдать ошибку.

Рекомендация: Всегда используйте функцию ВЫРАЗИТЬ в тексте запроса для приведения типов числовых полей и строк к тем значениям, которые определены в реквизитах формы. Например: ВЫРАЗИТЬ(Сумма(КБалл) КАК ЧИСЛО(10, 0)) КАК КБалл.

Управление видимостью и оформлением

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


// Скрываем служебные колонки, сохраняя их в составе данных
Элементы.ДеревоКритериевСотрудникСсылка.Видимость = Ложь;
Элементы.ДеревоКритериевЭтоГруппа.Видимость = Ложь;

// Если нужно развернуть все узлы дерева после загрузки
Для Каждого СтрокаДерева Из ДеревоКритериев.ПолучитьЭлементы() Цикл
    Идентификатор = СтрокаДерева.ПолучитьИдентификатор();
    Элементы.ДеревоКритериев.Развернуть(Идентификатор, Истина);
КонецЦикла;

Итоги

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

  1. Структурная идентичность: Колонки в ДеревоЗначений на сервере должны полностью совпадать с колонками в "Реквизитах" формы.
  2. Свойство «Использовать всегда»: Обязательно устанавливайте этот флаг для всех невидимых колонок реквизита.
  3. Контекстные методы: Используйте РеквизитФормыВЗначение для получения объекта и ЗначениеВРеквизитФормы для его записи обратно. Избегайте ЗначениеВДанныеФормы, если работаете со стандартными реквизитами, так как этот метод имеет более узкое применение.

Соблюдение этих принципов позволит вам избежать большинства трудностей при разработке сложных иерархических интерфейсов в системе 1С:Предприятие 8.3.

← На главную