При разработке универсальных механизмов в 1С часто возникает задача программного создания форм. Например, когда необходимо отобразить табличную часть произвольного документа или сформировать отчет с динамическим набором колонок. Однако многие разработчики сталкиваются с ошибкой "Недопустимое значение" при попытке установить свойство ПутьКДанным для нового элемента.
В этой статье мы подробно разберем, почему возникает эта ошибка, как правильно управлять жизненным циклом реквизитов формы и рассмотрим корректный алгоритм создания динамических таблиц.
Рассмотрим типичную ситуацию. Мы хотим программно добавить колонки в таблицу на форме, опираясь на метаданные объекта. Интуитивно разработчик пытается сделать все в одном цикле:
ПутьКДанным).Именно на 4-м шаге платформа выдает ошибку. Давайте проанализируем код, который приводит к сбою:
// ОШИБОЧНЫЙ ПОДХОД
Для каждого СтрокаТЧСсылки Из НайденнаяПоСсылкеТЧ.Реквизиты Цикл
// 1. Подготовка реквизита (но он еще не создан на форме!)
КолонкиДляДобавления.Добавить(Новый РеквизитФормы(СтрокаТЧСсылки.Имя, ...));
// 2. Создание элемента интерфейса
НовыйЭлемент = Элементы.Добавить("Колонка" + СтрокаТЧСсылки.Имя, Тип("ПолеФормы"), ТаблицаФормы);
НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
// 3. ОШИБКА ЗДЕСЬ
// Платформа еще не знает о существовании реквизита, так как ИзменитьРеквизиты еще не вызван
НовыйЭлемент.ПутьКДанным = "ТабличнаяЧастьОбъекта." + СтрокаТЧСсылки.Имя;
КонецЦикла;
// Только сейчас реквизиты реально создаются
ИзменитьРеквизиты(КолонкиДляДобавления);
Причина ошибки кроется в механизме работы управляемых форм. Свойство ПутьКДанным проверяет наличие реквизита в момент присвоения значения. Пока метод ИзменитьРеквизиты не отработал, новые поля существуют только в виде описаний в массиве КолонкиДляДобавления, но их нет в контексте формы.
Чтобы успешно создать динамическую форму, нам необходимо разделить процесс на два этапа. Это единственный архитектурно верный способ:
Рассмотрим исправленный алгоритм подробнее.
Сначала мы должны пройтись по метаданным и собрать массив объектов типа РеквизитФормы. Обратите внимание, что мы не трогаем коллекцию Элементы на этом этапе.
// Массивы для метода ИзменитьРеквизиты
КолонкиДляДобавления = Новый Массив;
КолонкиДляУдаления = Новый Массив;
// Предположим, мы очищаем старые колонки (получаем их имена заранее)
// ... логика заполнения КолонкиДляУдаления ...
// Формируем новые колонки на основе метаданных
Для каждого СтрокаТЧСсылки Из НайденнаяПоСсылкеТЧ.Реквизиты Цикл
// Создаем описание нового реквизита
// Важно: Путь "ТабличнаяЧастьОбъекта" указывает, что колонка принадлежит таблице
НовыйРеквизит = Новый РеквизитФормы(
СтрокаТЧСсылки.Имя, // Имя реквизита
СтрокаТЧСсылки.Тип, // Тип значения
"ТабличнаяЧастьОбъекта", // Путь к родительскому реквизиту (Имя таблицы на форме)
СтрокаТЧСсылки.Синоним // Заголовок
);
КолонкиДляДобавления.Добавить(НовыйРеквизит);
КонецЦикла;
// КРИТИЧЕСКИЙ МОМЕНТ: Применяем изменения структуры данных
// Именно здесь реквизиты физически появляются в контексте формы
ИзменитьРеквизиты(КолонкиДляДобавления, КолонкиДляУдаления);
Важно: Никогда не помещайте вызов ИзменитьРеквизиты внутрь цикла. Это очень тяжелая операция, которая перестраивает контекст формы. Вызов ее в цикле приведет к катастрофическому падению производительности.
Теперь, когда структура данных формы обновлена, мы можем смело создавать визуальные элементы. Платформа уже "видит" новые поля таблицы, поэтому проверка ПутьКДанным пройдет успешно.
// Второй проход по тем же метаданным (или по массиву добавленных имен)
Для каждого СтрокаТЧСсылки Из НайденнаяПоСсылкеТЧ.Реквизиты Цикл
// Формируем уникальное имя элемента формы
ИмяЭлемента = "Колонка" + СтрокаТЧСсылки.Имя;
// Добавляем элемент в коллекцию элементов формы
// Третий параметр - родитель (наша таблица формы)
НовыйЭлемент = Элементы.Добавить(ИмяЭлемента, Тип("ПолеФормы"), ТаблицаФормы);
// Настраиваем вид
НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
// Устанавливаем связь с данными
// Теперь это сработает, так как реквизит "ТабличнаяЧастьОбъекта.ИмяКолонки" уже существует
НовыйЭлемент.ПутьКДанным = "ТабличнаяЧастьОбъекта." + СтрокаТЧСсылки.Имя;
НовыйЭлемент.Заголовок = СтрокаТЧСсылки.Синоним;
НовыйЭлемент.Ширина = 20;
КонецЦикла;
При программной работе важно правильно формировать строку для свойства ПутьКДанным. Ошибка в одной точке приведет к неработоспособности.
Элемент.ПутьКДанным = "ИмяРеквизита";Элемент.ПутьКДанным = "Объект.ИмяРеквизита";Элемент.ПутьКДанным = "ИмяТаблицыЗначений.ИмяКолонки";Элемент.ПутьКДанным = "Объект.ИмяТабличнойЧасти.ИмяКолонки";В разобранном примере использовался вариант с Таблицей Значений, являющейся реквизитом формы, поэтому правильный путь выглядел как "ТабличнаяЧастьОбъекта." + ИмяКолонки.
Рассмотрим еще несколько моментов, которые помогут избежать ошибок при динамическом создании форм:
Элементы.Удалить().РеквизитФормы обратите внимание на перенос типов. Простое копирование СтрокаТЧСсылки.Тип работает в 99% случаев, но если используются сложные составные типы или уникальные характеристики, может потребоваться создание нового объекта ОписаниеТипов.ПриИзменении). Если вам нужна интерактивность, используйте метод УстановитьДействие.
// Пример установки обработчика события
НовыйЭлемент.УстановитьДействие("ПриИзменении", "Подключаемый_ПриИзмененииКолонки");
Подводя итог: секрет успеха в программном создании форм — строгая последовательность. Сначала создаем данные (реквизиты) и фиксируем их, и только потом строим интерфейс (элементы), привязывая его к готовым данным.