Как программно установить действие «После», «Перед» или «Вместо» в расширении 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке расширений для платформы 1С:Предприятие 8.3 программисты часто сталкиваются с необходимостью программного назначения обработчиков событий для элементов формы (например, для события ПриИзменении поля ввода). Однако стандартный метод УстановитьДействие не содержит параметров для указания типа перехвата: «Перед», «После» или «Вместо». В этой статье мы подробно разберем, почему так происходит, и какими способами можно добиться нужного поведения платформы, используя только программный код. Для этих целей есть настройка обработчиков событий без программирования.

Особенности работы метода УстановитьДействие в расширениях

Для начала проанализируем ситуацию: метод УстановитьДействие предназначен для жесткой связи события элемента управления с конкретной процедурой модуля формы. Когда мы вызываем этот метод для элемента, который уже существует в основной конфигурации, платформа просто заменяет старый обработчик новым. Директивы расширений, такие как &После или &Перед, работают на уровне компиляции модулей, а не на уровне динамического назначения связей элементов. Удобнее анализировать такие расширения через инструмент для архитектурного анализа расширений.

Рассмотрим подробнее три основных способа решения этой задачи в зависимости от контекста вашей разработки — для этого подойдёт обработка для расширения логики без изменения конфигурации.

Способ 1. Использование аннотаций в модуле расширения (рекомендуемый)

Если элемент формы и его обработчик уже существуют в основной конфигурации, нам вообще не нужно использовать метод УстановитьДействие. Платформа 1С автоматически выполнит перехват, если мы правильно опишем процедуру в модуле формы расширения. Это самый «чистый» способ, который сохраняет типовую логику и добавляет нашу собственную.

Выполним следующие шаги:

  1. Определим имя процедуры-обработчика в основной конфигурации (например, НоменклатураПриИзменении).
  2. В модуле формы расширения создадим процедуру с таким же набором параметров.
  3. Используем аннотацию &После, &Перед или &Вместо.

&НаКлиенте
&После("НоменклатураПриИзменении")
Процедура Расшир1_НоменклатураПриИзмененииПосле(Элемент)
    // Ваш код, который выполнится ПОСЛЕ типового
    Сообщить("Данные успешно изменены и обработаны расширением!");
КонецПроцедуры

Важный нюанс: этот метод работает только в том случае, если в основной конфигурации физически существует процедура НоменклатураПриИзменении. Если обработчик в основной конфигурации не назначен, аннотация не сработает или вызовет ошибку при компиляции (в зависимости от версии платформы).

Способ 2. Программная эмуляция «После» через выполнение старого действия

Рассмотрим ситуацию, когда нам необходимо динамически подменить обработчик, но при этом гарантированно выполнить старый код, который был назначен элементу ранее. Мы можем получить имя старого обработчика, назначить свой, а внутри своего кода вызвать старый через функцию Выполнить или через прямое обращение к контексту.

Разберем пример реализации, который позволяет избежать зацикливания события:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // 1. Добавляем вспомогательный реквизит для контроля выполнения, чтобы избежать рекурсии
    ДобавляемыеРеквизиты = Новый Массив;
    НовыйРеквизит = Новый РеквизитФормы("ПИК_Выполнено", Новый ОписаниеТипов("Булево"));
    ДобавляемыеРеквизиты.Добавить(НовыйРеквизит);
    ЭтаФорма.ИзменитьРеквизиты(ДобавляемыеРеквизиты);
    
    // 2. Устанавливаем наш программный обработчик
    Элементы.БанковскийСчет.УстановитьДействие("ПриИзменении", "ПИК_БанковскийСчетПриИзмененииПосле");
КонецПроцедуры

&НаКлиенте
Процедура ПИК_БанковскийСчетПриИзмененииПосле(Элемент)
    // Имя оригинальной процедуры, которую мы хотим "обернуть"
    ИмяСтарогоДействия = "БанковскийСчетПриИзменении(Элемент)";
    
    Если Не ЭтаФорма.ПИК_Выполнено Тогда
        ЭтаФорма.ПИК_Выполнено = Истина;
        
        // Выполняем типовой код
        Попытка
            Выполнить(ИмяСтарогоДействия);
        Исключение
            // Обработка случая, если процедура не найдена или недоступна
        КонецПопытки;
        
        ЭтаФорма.ПИК_Выполнено = Ложь;
    КонецЕсли;

    // Здесь пишем наш код, который должен сработать "ПОСЛЕ"
    ОбновитьСвязанныеДанныеНаФорме();
КонецПроцедуры

Внимание: Использование Выполнить() может быть ограничено требованиями безопасности в некоторых конфигурациях или при работе в веб-клиенте — поможет инструмент для отладки кода в режиме предприятия. Начиная с платформы 8.3.15, рекомендуется использовать метод ЭтотОбъект[ИмяПроцедуры](Параметры), если процедура является экспортной.

Способ 3. Гибридный подход для динамических элементов

Бывают случаи, когда элемент формы создается программно в расширении, или когда мы не знаем заранее, добавит ли вендор обработчик в обновлении основной конфигурации. В этом случае проанализируем состояние элемента в событии ПриСозданииНаСервере.

Логика работы будет следующей: проверим через ПолучитьДействие, назначен ли уже какой-то обработчик. Если поле пустое — назначаем свой. Если не пустое — полагаемся на механизм аннотаций &После.


&НаСервере
Процедура Расшир_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
    // Проверяем, назначен ли обработчик в основной конфигурации
    ТекущееДействие = Элементы.Товары.ПолучитьДействие("ПриНачалеРедактирования");
    
    Если ПустаяСтрока(ТекущееДействие) Тогда
        // Если обработчика нет, назначаем свой напрямую
        Элементы.Товары.УстановитьДействие("ПриНачалеРедактирования", "Расшир_ТоварыПриНачалеРедактирования");
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
&После("ТоварыПриНачалеРедактирования")
Процедура Расшир_ТоварыПриНачалеРедактирования(Элемент, НоваяСтрока, Копирование)
    // Этот код сработает:
    // 1. Через прямую установку (если типового обработчика нет)
    // 2. Через механизм &После (если типовой обработчик появился после обновления)
    
    Если Копирование Тогда
        // Наша дополнительная логика
        Элементы.Товары.ТекущиеДанные.ИдентификаторСтроки = Новый УникальныйИдентификатор;
    КонецЕсли;
КонецПроцедуры

Ограничения и рекомендации

Проанализировав возможности платформы, важно выделить несколько критических моментов:

  1. Контекст выполнения: Обработчик, указываемый в УстановитьДействие, обязан находиться в модуле этой же формы. Вы не можете напрямую указать процедуру из общего модуля или модуля другой формы. Если вам нужно вызвать общий модуль, создайте «процедуру-прослойку» в модуле формы.
  2. Конфликты обновлений: Принудительная установка действия через УстановитьДействие полностью заменяет типовой код. Если разработчики основной конфигурации добавят критически важную логику в это событие, ваше расширение ее «затрет». Поэтому всегда старайтесь использовать проверку ПолучитьДействие или стандартные аннотации.
  3. Зацикливание: При программном вызове событий (особенно ПриИзменении) легко попасть в бесконечный цикл. Использование флагов (как в Примере 2) — обязательная практика при сложных манипуляциях с программными вызовами.

Таким образом, хотя платформа не предоставляет прямого параметра УстановитьДействие(..., "После"), комбинирование программной проверки ПолучитьДействие и аннотаций в модуле формы позволяет реализовать любую сложную логику взаимодействия расширения и основной конфигурации. В работе поможет комплекс инструментов для разработчика 1С.

← На главную