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