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