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