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