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