При разработке на платформе 1С 8.3 в режиме управляемого приложения программисты часто сталкиваются с необходимостью отображения сложных иерархических структур на форме. Стандартный подход подразумевает создание программного объекта ДеревоЗначений на стороне сервера (например, в результате выполнения запроса) и последующую его передачу в реквизит формы, имеющий тип ДанныеФормыДерево. Однако на этапе вызова метода ЗначениеВРеквизитФормы нередко возникает критическая ошибка: «Ошибка при вызове метода контекста (ЗначениеВРеквизитФормы) по причине: Недопустимое значение параметра (параметр номер '2')».
В этой статье мы подробно разберем, почему возникает эта проблема, проанализируем механизмы работы с коллекциями управляемых форм и предложим несколько способов надежного решения задачи.
Проанализируем ситуацию: у нас есть объект ДеревоЗначений (сокращенно ДЗ), заполненный данными из запроса, и реквизит управляемой формы с типом ДанныеФормыДерево. Казалось бы, метод ЗначениеВРеквизитФормы(ДЗ, "ИмяРеквизита") должен автоматически синхронизировать данные, но платформа выдает ошибку.
Главная причина кроется в структурном несоответствии колонок. Рассмотрим нюансы, которые критически важны для работы платформы:
ДеревоЗначений обязательно должны присутствовать все колонки, которые определены в реквизите формы ДанныеФормыДерево. Если в экранной форме вы добавили колонку «Статус», а в результате запроса в ДеревоЗначений такой колонки нет — метод выдаст ошибку недопустимого значения.ДеревоЗначений есть дополнительные технические колонки, которых нет в реквизите формы, система их просто проигнорирует при копировании.ID_Node и id_node могут вызвать конфликт в некоторых версиях платформы).Вывод: Подмножество колонок реквизита формы должно полностью пересекаться с множеством колонок загружаемого дерева. Проверьте через конфигуратор состав колонок реквизита и убедитесь, что в коде создания ДеревоЗначений они все инициализированы.
Разберем подробнее, какой метод использовать. В контексте управляемых форм существует два похожих инструмента:
ЗначениеВРеквизитФормы — используется, когда нам нужно обновить данные реквизита, который жестко задан в редакторе формы. Он не только копирует данные, но и сообщает форме, что данные изменились, что может инициировать перерисовку связанных элементов интерфейса.ЗначениеВДанныеФормы — более универсальный метод, который часто применяется для заполнения коллекций, не являющихся основными реквизитами, или при работе с программно созданными структурами данных.Если ошибка возникает в одном методе, простая замена на другой редко помогает, так как требования к составу колонок у них идентичны. Однако проверьте правильность написания пути к реквизиту во втором параметре — это должна быть строка с точным именем реквизита из свойств формы.
Посмотрим на ситуацию глубже. Даже если имена колонок совпадают, платформа может «споткнуться» на типах данных. Если в ДанныеФормыДерево для колонки задан конкретный тип (например, Число(10, 0)), а в ДеревоЗначений колонка создана без указания типа (тип Произвольный), преобразование может завершиться ошибкой.
Рекомендуем явно типизировать колонки при программном создании дерева. Рассмотрим пример правильной подготовки структуры:
// Описываем типы для колонок
МассивТиповСтрока = Новый Массив;
МассивТиповСтрока.Добавить(Тип("Строка"));
ОписаниеТиповСтрока = Новый ОписаниеТипов(МассивТиповСтрока);
ДЗ = Новый ДеревоЗначений;
// Важно: Имя колонки должно совпадать с именем в реквизитах формы!
ДЗ.Колонки.Добавить("НаименованиеKPI", ОписаниеТиповСтрока);
ДЗ.Колонки.Добавить("Значение", Новый ОписаниеТипов("Число"));
Проанализируем ситуацию, когда автоматические методы не подходят (например, из-за слишком сложной структуры или динамически меняющихся имен). В этом случае мы можем прибегнуть к рекурсивному обходу дерева. Это исключит системные ошибки преобразования типов и даст полный контроль над процессом.
Рассмотрим алгоритм ручного заполнения:
&НаСервере
Процедура ЗаполнитьДеревоНаФорме(ИсточникДЗ)
// Очищаем существующие данные в реквизите формы
ЭлементыКоллекцииФормы = ДеревоKPI7.ПолучитьЭлементы();
ЭлементыКоллекцииФормы.Очистить();
// Запускаем рекурсию для каждой строки верхнего уровня
Для Каждого СтрокаИсточник Из ИсточникДЗ.Строки Цикл
НоваяСтрокаФормы = ЭлементыКоллекцииФормы.Добавить();
ЗаполнитьРекурсивно(СтрокаИсточник, НоваяСтрокаФормы);
КонецЦикла;
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьРекурсивно(СтрокаИсточник, СтрокаПриемник)
// Копируем значения по совпадающим именам колонок
ЗаполнитьЗначенияСвойств(СтрокаПриемник, СтрокаИсточник);
// Обходим подчиненные строки
Для Каждого ПодчиненнаяИсточник Из СтрокаИсточник.Строки Цикл
ПодчиненнаяПриемник = СтрокаПриемник.ПолучитьЭлементы().Добавить();
ЗаполнитьРекурсивно(ПодчиненнаяИсточник, ПодчиненнаяПриемник);
КонецЦикла;
КонецПроцедуры
Этот способ медленнее, чем ЗначениеВРеквизитФормы, на больших объемах данных, но он гарантирует отсутствие ошибок при несовпадении структур.
Если вы заполняете ДеревоЗначений результатом запроса с использованием предложения ИТОГИ, убедитесь, что иерархия строится корректно. Платформа 1С ожидает, что структура вложенности строк в объекте ДеревоЗначений логически соответствует ожиданиям элемента управления «Поле дерева». Любые «битые» ссылки в родительских узлах могут привести к непредсказуемому поведению при попытке выгрузки данных в форму.
Завершая разбор проблемы, выделим несколько ключевых моментов, которые помогут избежать ошибок в будущем:
ЗначениеВРеквизитФормы в отладчике сравните количество и имена колонок в ДЗ.Колонки и в свойствах реквизита на закладке «Реквизиты» формы.КопироватьДанныеФормы(Источник, Приемник). Это гораздо быстрее, так как не требует преобразования в «прикладной» объект ДеревоЗначений.ЗначениеВРеквизитФормы полностью перезаписывает структуру строк. Это приведет к тому, что все развернутые пользователем узлы дерева в интерфейсе свернутся, а фокус с текущей строки пропадет. Если это критично, используйте ручное обновление только изменившихся узлов.Таким образом, успех преобразования дерева значений в данные формы зависит прежде всего от идентичности структуры колонок и корректности типов данных. Следуя этим правилам, вы сможете избежать ошибки недопустимого значения параметра и обеспечить стабильную работу интерфейса вашего приложения.