Как назначить обработчик события в форме и модуле 1С

· 9 мин

Содержание

Обработчик назначают в трёх местах: для события элемента или формы — через палитру свойств в редакторе форм (кнопка с лупой рядом с событием создаёт процедуру в модуле формы); для события объекта (ПередЗаписью, ПриЗаписи) — в модуле объекта; для чужого объекта без правки его модуля — через подписку на события в дереве конфигурации.

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

Где возникают события и какие бывают обработчики

События в платформе делятся по тому, кто их порождает:

  • 🖱️ События элементов формы — реакция на действия пользователя: ПриИзменении поля, Нажатие кнопки, Выбор в списке, АвтоПодбор в строке ввода. Выполняются на клиенте.
  • 🪟 События формы — жизненный цикл формы: ПриСозданииНаСервере, ПриОткрытии, ПередЗакрытием, ПриПовторномОткрытии. Часть выполняется на сервере, часть на клиенте.
  • 💾 События объекта — запись и проверка данных: ПередЗаписью, ПриЗаписи, ПередУдалением, ОбработкаПроверкиЗаполнения, ОбработкаЗаполнения. Выполняются на сервере, в модуле объекта.

Одно и то же действие может поднять цепочку событий. Нажали «Провести и закрыть» — сработают клиентское ПередЗаписью формы, затем серверные ПередЗаписью и ПриЗаписи объекта, потом ОбработкаПроведения. Понимание порядка важно: если проверку поставить не в то событие, она либо не остановит запись, либо сработает слишком поздно.

Отдельно стоит развести два события, которые часто путают при открытии формы. ПриСозданииНаСервере выполняется на сервере один раз при создании формы — сюда ставят заполнение реквизитов значениями по умолчанию, настройку видимости и доступности элементов, установку условного оформления. ПриОткрытии выполняется позже и уже на клиенте — здесь уместны действия, которым нужен клиент: открытие вспомогательной формы, вопрос пользователю, запуск оповещения. Если заполнение данных поставить в ПриОткрытии, оно будет происходить после того, как форма уже показана, и пользователь успеет увидеть пустые поля.

Полный список событий конкретного объекта или элемента всегда виден в палитре свойств в разделе «События» — платформа показывает только те, что применимы к выделенному объекту.

Назначение обработчика в редакторе форм

Самый частый способ. Открываете форму в конфигураторе (ветка Формы объекта → двойной клик по форме), выделяете элемент или корень формы.

  1. Откройте палитру свойств: правый клик по элементу → Свойства, либо Alt+Enter.
  2. Прокрутите до раздела События.
  3. Найдите нужное событие (например, ПриИзменении у поля ввода).
  4. Нажмите кнопку с лупой справа от строки события.

Платформа создаст в модуле формы процедуру с правильным именем и директивой компиляции и свяжет её со свойством события. Имя по умолчанию складывается из имени элемента и события: у поля Цена обработчик ПриИзменении получит имя ЦенаПриИзменении.

&НаКлиенте
Процедура ЦенаПриИзменении(Элемент)
    Сумма = Количество * Цена;
КонецПроцедуры
Назначение обработчика в форме
Выполнено: 0 / 6

Если процедура уже есть и вы хотите привязать её вручную, впишите имя в строку события без скобок и параметров — просто ЦенаПриИзменении. Привязка идёт по имени: переименуете процедуру в модуле — обязательно поправьте имя в свойстве события, иначе обработчик перестанет вызываться.

Для кнопки принцип тот же. Выделите кнопку, в разделе «События» найдите Нажатие, нажмите лупу. Внутри обработчика размещаете то, что должно происходить по нажатию:

&НаКлиенте
Процедура РассчитатьНажатие(Кнопка)
    Если НЕ ЗначениеЗаполнено(Контрагент) Тогда
        Сообщить("Сначала выберите контрагента");
        Возврат;
    КонецЕсли;
    ВыполнитьРасчётНаСервере();
КонецПроцедуры

Обратите внимание на параметр процедуры: у события ПриИзменении платформа передаёт Элемент, у Нажатие — Кнопка. Набор параметров у каждого события свой и менять его нельзя — удалите лишний параметр, и код не скомпилируется. Поэтому заготовку надёжнее получать лупой: она подставит правильную сигнатуру.

Для работы с выбором значений пригодятся два связанных события. Выбор у поля ввода срабатывает, когда пользователь жмёт кнопку выбора и открывает форму подбора. ОбработкаВыбора — событие уже самой формы: оно отрабатывает, когда из открытой формы подбора вернулось значение (форма подбора отдаёт его методом ОповеститьОВыборе). Эту пару назначают, когда нужен нестандартный подбор — например, открыть свою форму списка с предварительным отбором вместо стандартного выбора из справочника.

Обработчики в модуле объекта

События записи, удаления и проверки живут не в форме, а в модуле объекта. Форм у справочника или документа может быть несколько, а модуль объекта один — поэтому логику записи размещают именно там.

Открыть модуль : в дереве конфигурации правый клик по объекту → Открыть модуль объекта. В верхней части редактора модуля есть выпадающий список процедур-обработчиков — выберите нужное событие, и платформа вставит заготовку.

Типичный обработчик проверки перед записью:

Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
    Если ЗначениеЗаполнено(Контрагент) И НЕ ЗначениеЗаполнено(ДоговорКонтрагента) Тогда
        Сообщить("Не выбран договор");
        Отказ = Истина;
    КонецЕсли;
КонецПроцедуры

Процедуры модуля объекта выполняются на сервере — директива компиляции здесь не ставится. Через параметр Отказ = Истина вы отменяете запись: платформа прервёт операцию и вернёт пользователю сообщение.

СобытиеКогда срабатываетДля чего использовать
ОбработкаПроверкиЗаполненияпо команде проверки и перед записьюконтроль обязательных полей
ПередЗаписьюдо начала записи в транзакцииподготовка данных, отказ от записи
ПриЗаписивнутри транзакции записизапись связанных данных
ПередУдалениемдо удаления объектапроверка ссылок, запрет удаления

Код в ПриЗаписи выполняется внутри транзакции. Долгие операции и обращения к внешним системам сюда не ставьте — транзакция будет держать блокировки, пока код не отработает.

Подписки на события: обработка без правки модуля

Отдельный механизм, который экономит время практику. Подписка позволяет назначить обработчик события сразу для нескольких объектов и не трогать их модули — удобно, когда правите типовую конфигурацию и хотите обойтись расширением.

Создаётся в дереве: ветка Общие → Подписки на события → добавить. У подписки три главных свойства:

  • Источник — составной тип: отметьте объекты, чьё событие перехватываете (например, несколько документов сразу).
  • Событие — выбирается из списка доступных для выбранных источников (ПередЗаписью, ПриЗаписи и т. д.).
  • Обработчик — экспортная процедура в общем модуле.

Общий модуль, где лежит обработчик, должен компилироваться на сервере (флаг Сервер в свойствах модуля). Сигнатура процедуры повторяет параметры события плюс первым идёт источник:

// Общий модуль с флагом «Сервер»
Процедура ПроверитьДатуДокумента(Источник, Отказ) Экспорт
    Если Источник.Дата < НачалоГода(ТекущаяДата()) Тогда
        Отказ = Истина;
    КонецЕсли;
КонецПроцедуры

Подписки на события и обработчики в самих модулях объектов выполняются независимо — для одного события отработают оба. Если их несколько, порядок вызова подписок платформой не гарантируется, поэтому не стройте логику на том, что одна подписка выполнится раньше другой.

Директивы компиляции: клиент, сервер и контекст

В модуле управляемой формы каждая процедура помечается директивой — она определяет, где код выполняется и имеет ли доступ к данным формы.

  • &НаКлиенте — на клиенте, есть контекст формы. Сюда идут обработчики событий элементов, потому что действия пользователя происходят на клиенте.
  • &НаСервере — на сервере, с контекстом формы: можно читать и менять реквизиты формы, обращаться к базе.
  • &НаСервереБезКонтекста — на сервере, без контекста формы. Работает быстрее, годится для вспомогательных расчётов, которым форма не нужна.
  • &НаКлиентеНаСервереБезКонтекста — компилируется и там, и там.

Ключевое правило: обработчик события элемента формы вызывается на клиенте, поэтому он всегда &НаКлиенте. Если внутри нужно обратиться к базе, вынесите эту часть в серверную процедуру и вызовите её:

&НаКлиенте
Процедура КонтрагентПриИзменении(Элемент)
    ЗаполнитьДоговорПоУмолчанию();
КонецПроцедуры

&НаСервере
Процедура ЗаполнитьДоговорПоУмолчанию()
    Договор = Справочники.ДоговорыКонтрагентов.ОсновнойДоговор(Контрагент);
КонецПроцедуры

Событие ПриСозданииНаСервере само по себе серверное (&НаСервере), а ПриОткрытии и ПередЗакрытием — клиентские (&НаКлиенте). Лупа в палитре свойств подставляет правильную директиву автоматически — это ещё один повод создавать обработчики через неё, а не вписывать вручную.

Динамическое назначение обработчика в коде

Иногда обработчик нужно привязать не в конструкторе, а программно — например, в зависимости от настроек. Для элементов формы есть метод УстановитьДействие:

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Элементы.Цена.УстановитьДействие("ПриИзменении", "ЦенаПриИзменении");
КонецПроцедуры

Первый параметр — имя события строкой, второй — имя клиентской процедуры модуля формы (тоже строкой). Процедура ЦенаПриИзменении должна существовать в модуле с директивой &НаКлиенте. Пустая строка во втором параметре снимает обработчик.

Для событий прикладных объектов в коде есть пара операторов ДобавитьОбработчик и УдалитьОбработчик:

ДобавитьОбработчик Источник.ПередЗаписью, ЭтотОбъект.ПроверкаПередЗаписью;

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

Важная тонкость: программная установка значения реквизита не вызывает событие ПриИзменении. Платформа поднимает его только на действие пользователя. Если присвоили значение в коде и нужна та же логика — вызовите процедуру пересчёта напрямую.

Отладка обработчиков и типичные ошибки

Проверить, что обработчик назначен и вызывается, проще всего отладчиком. Поставьте точку останова (F9) на первой строке процедуры, запустите приложение в режиме отладки и выполните действие. Если управление в процедуру не зашло — обработчик не привязан или вы ждёте событие, которое при этом действии не поднимается.

Инструменты отладки:

  • Точка останова (F9) — остановка на строке.
  • Шаг с заходом / с обходом (F11 / F10) — построчное выполнение.
  • Табло — просмотр значений переменных в момент останова.
  • Остановка по ошибке — настраивается в меню отладки, ловит исключение в момент возникновения.
Диагностика: выберите симптом

Ещё одна частая путаница — клиент и сервер. Внутри клиентского обработчика нельзя напрямую читать базу и вызывать серверные методы объектов; нужно уйти на сервер отдельной процедурой. И наоборот: из серверной процедуры без контекста (&НаСервереБезКонтекста) не видны реквизиты формы — обращение к ним даст ошибку компиляции.

Частые вопросы

Чем модуль формы отличается от модуля объекта?
Модуль формы обслуживает одну конкретную форму и её элементы, его процедуры делятся на клиентские и серверные директивами. Модуль объекта один на объект, выполняется на сервере и отвечает за запись, проверку и удаление данных.
Можно ли назначить один обработчик на несколько элементов?
Да. Создайте процедуру и впишите её имя в свойство события у каждого элемента вручную. Различить, кто вызвал обработчик, поможет параметр Элемент, который платформа передаёт в процедуру.
Как снять ранее назначенный обработчик?
В палитре свойств очистите строку события. Программно — вызовите УстановитьДействие с пустой строкой во втором параметре для элемента формы или оператор УдалитьОбработчик для события объекта.
Почему обработчик `ПередЗаписью` не останавливает запись?
Запись отменяет только Отказ = Истина внутри процедуры. Если просто вывели сообщение без установки Отказ, платформа продолжит запись. Проверьте, что присваиваете параметру Отказ значение Истина.
Что выполнится раньше — обработчик в модуле объекта или подписка?
Оба отработают для одного события. Гарантированного порядка между подписками платформа не даёт, поэтому не завязывайте логику на очерёдность — держите в каждом обработчике самостоятельную проверку.