Где и как подключить свою процедуру к событию формы, объекта или всей программы в 1С 8.3

· 10 мин

Содержание

Чтобы добавить обработчик события в 1С, откройте объект в Конфигураторе, выделите форму или её элемент, в палитре свойств найдите группу «События» и нажмите кнопку с лупой рядом с нужным событием. Платформа сама создаст процедуру в модуле формы и свяжет её с событием. Для событий документа или справочника процедуру пишут в модуле объекта, а для реакции сразу на много объектов — создают подписку на события.

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

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

Платформа сама вызывает процедуры с заранее известными именами или процедуры, которые вы явно привязали к событию. Отсюда два способа связи:

  • 🔗 По привязке — в свойствах формы или элемента указано имя процедуры. Так работают все события форм, элементов и команд. Имя может быть любым.
  • 📛 По имени — процедура в модуле называется ровно как событие: ПередЗаписью, ОбработкаПроведения, ПриНачалеРаботыСистемы. Так работают модули объектов, менеджеров, приложения и сеанса.
  • 📣 Через подписку — объект метаданных «Подписка на событие» связывает событие многих объектов с одной экспортной процедурой общего модуля.

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

ДирективаГде выполняетсяДоступ к данным формыКогда брать
&НаКлиентеклиентдареакция интерфейса, вопросы пользователю
&НаСервересерверда, форма передаётся на серверзапросы к базе с использованием реквизитов формы
&НаСервереБезКонтекстасервернетбыстрый серверный вызов, данные передаются параметрами

Модули объектов, менеджеров и серверные общие модули исполняются на сервере, директивы там не нужны.

Если серверной процедуре нужны два-три значения с формы, выбирайте &НаСервереБезКонтекста и передавайте их параметрами. Вызов без контекста не гоняет всю форму между клиентом и сервером и заметно быстрее на медленных каналах.

Обработчик события формы: создаём через палитру свойств

События самой формы — открытие, создание, закрытие, запись, оповещения — подключаются так:

  1. В дереве конфигурации раскройте объект, ветку «Формы» и откройте нужную форму двойным щелчком.
  2. В верхнем левом дереве элементов выделите корневой элемент «Форма».
  3. Откройте палитру свойств (Alt+Enter или правая кнопка → «Свойства»).
  4. Пролистайте до группы «События».
  5. Щёлкните по строке события, например ПриОткрытии, и нажмите кнопку с лупой справа.
  6. Для событий, у которых есть выбор, платформа спросит, где создать обработчик: на клиенте, на клиенте с серверной процедурой или на клиенте с серверной процедурой без контекста. Выберите вариант по таблице выше.

Конфигуратор добавит в модуль формы процедуру с правильными параметрами и откроет её. Имя по умолчанию совпадает с событием, а в свойстве появится ссылка на неё.

Самые ходовые события формы:

СобытиеГдеДля чего
ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)серверустановить начальные значения, скрыть элементы по правам
ПриОткрытии(Отказ)клиентдействия после показа формы
ПриЧтенииНаСервере(ТекущийОбъект)сервердочитать данные при открытии существующего объекта
ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)серверперенести данные формы в объект перед записью
ПослеЗаписи(ПараметрыЗаписи)клиентоповестить другие формы, обновить интерфейс
ОбработкаОповещения(ИмяСобытия, Параметр, Источник)клиентреагировать на Оповестить() из других форм
ПередЗакрытием(...)клиентпредупредить о несохранённых данных

Пример: при создании нового документа подставляем текущего пользователя в реквизит «Ответственный».

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

	Если Объект.Ссылка.Пустая() Тогда
		Объект.Ответственный = Пользователи.ТекущийПользователь();
	КонецЕсли;

КонецПроцедуры

Пользователи.ТекущийПользователь() есть в конфигурациях на БСП (БП 3.0, ЗУП 3.1, УТ 11). В самописной конфигурации без БСП берите ПользователиИнформационнойБазы.ТекущийПользователь() и ищите элемент справочника сами.

События реквизитов и элементов формы

У каждого поля, таблицы и кнопки на форме свой набор событий. Порядок тот же: выделите элемент в дереве элементов, откройте свойства, группа «События», кнопка с лупой.

Поле ввода: ПриИзменении и НачалоВыбора

Чаще всего пересчитывают что-то при смене значения. Обработчик поля «Контрагент» получит имя КонтрагентПриИзменении:

&НаКлиенте
Процедура КонтрагентПриИзменении(Элемент)
	КонтрагентПриИзмененииНаСервере();
КонецПроцедуры

&НаСервере
Процедура КонтрагентПриИзмененииНаСервере()
	Объект.Договор = Справочники.ДоговорыКонтрагентов.ПустаяСсылка();
КонецПроцедуры

Событие НачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка) срабатывает при нажатии кнопки выбора. Поставьте СтандартнаяОбработка = Ложь, и стандартная форма выбора не откроется — можно показать свой список.

Колонка табличной части

Обработчики колонок называются по схеме «ИмяТаблицыИмяКолонкиСобытие». Текущую строку берите через ТекущиеДанные:

&НаКлиенте
Процедура ТоварыКоличествоПриИзменении(Элемент)

	СтрокаТЧ = Элементы.Товары.ТекущиеДанные;
	Если СтрокаТЧ = Неопределено Тогда
		Возврат;
	КонецЕсли;

	СтрокаТЧ.Сумма = СтрокаТЧ.Количество * СтрокаТЧ.Цена;

КонецПроцедуры

У самой таблицы формы есть свои события: ПриАктивизацииСтроки, ПередНачаломДобавления, ПередУдалением, ПриОкончанииРедактирования, Выбор.

Подключение из кода

Иногда элемент создают программно — тогда событие привязывают методом УстановитьДействие:

&НаСервере
Процедура ДобавитьПолеКомментарий()

	Поле = Элементы.Добавить("ПолеКомментарий", Тип("ПолеФормы"), Элементы.ГруппаШапка);
	Поле.Вид = ВидПоляФормы.ПолеВвода;
	Поле.ПутьКДанным = "Объект.Комментарий";
	Поле.УстановитьДействие("ПриИзменении", "ПолеКомментарийПриИзменении");

КонецПроцедуры

Процедура ПолеКомментарийПриИзменении должна уже существовать в модуле формы с директивой &НаКлиенте.

Обработчики команд формы

Кнопка на форме — это обычно команда:

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

Если кнопка есть, а при нажатии ничего не происходит, первым делом проверьте свойство «Действие» у команды: оно не должно быть пустым.

Обработчики в модуле объекта: документы и справочники

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

Как открыть модуль : двойной щелчок по документу или справочнику в дереве конфигурации → вкладка «Прочее» → кнопка «Модуль объекта». Или правая кнопка по объекту в дереве → «Открыть модуль объекта».

Обработчики пишутся вручную по имени события, с точной сигнатурой:

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

Пример: запрещаем записывать поступление без номера входящего документа, кроме загрузки из обмена.

Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)

	Если ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;

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

КонецПроцедуры

Проверка ОбменДанными.Загрузка в начале обработчика — привычка опытных разработчиков. При загрузке из обмена объект приходит уже готовым, и ваши проверки там только мешают.

ОбщегоНазначения.СообщитьПользователю — процедура БСП. Без БСП создайте Новый СообщениеПользователю, заполните Текст и вызовите Сообщить(), а Отказ = Истина установите отдельной строкой.

Подписки на события и общие модули

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

Шаг 1. Общий модуль

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

	Если Источник.ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;

	Если Не ЗначениеЗаполнено(Источник.Склад) Тогда
		Отказ = Истина;
		Сообщение = Новый СообщениеПользователю;
		Сообщение.Текст = "Не заполнен склад";
		Сообщение.Сообщить();
	КонецЕсли;

КонецПроцедуры

Шаг 2. Подписка

  1. Общие → Подписки на события → «Добавить».
  2. В свойстве «Источник» отметьте типы объектов, например ДокументОбъект.ПоступлениеТоваровУслуг и ДокументОбъект.РеализацияТоваровУслуг. Обратите внимание: тип именно ...Объект, а не ссылка.
  3. В свойстве «Событие» выберите ПередЗаписью.
  4. В свойстве «Обработчик» выберите процедуру из общего модуля.

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

Модули приложения и сеанса — глобальные события

События уровня всей программы находятся в модулях конфигурации. Откройте их через правую кнопку по корню дерева конфигурации:

  • 🖥 Модуль управляемого приложения — клиентские события ПередНачаломРаботыСистемы(Отказ), ПриНачалеРаботыСистемы(), ПередЗавершениемРаботыСистемы(Отказ, ТекстПредупреждения), ПриЗавершенииРаботыСистемы().
  • 🔐 Модуль сеанса — серверное событие УстановкаПараметровСеанса(ТребуемыеПараметры): здесь заполняют параметры сеанса.
  • 🔌 Модуль внешнего соединения — те же события начала и завершения, но для COM-подключений.

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

&НаКлиенте
Процедура ПриОткрытии(Отказ)
	ПодключитьОбработчикОжидания("ОбновитьСтатус", 60);
КонецПроцедуры

&НаКлиенте
Процедура ОбновитьСтатус() Экспорт
	// обновление раз в 60 секунд
КонецПроцедуры

Отключают его через ОтключитьОбработчикОжидания("ОбновитьСтатус"). Третий параметр Истина в ПодключитьОбработчикОжидания делает вызов однократным.

Как добавить обработчик в типовую конфигурацию через расширение

В БП 3.0, ЗУП 3.1, УТ 11 правка основной конфигурации снимает её с полной поддержки и усложняет обновления. Добавлять обработчики в типовые лучше расширением (механизм появился в 8.3.6).

  1. Конфигурация → Расширения конфигурации → «Добавить».
  2. В дереве основной конфигурации найдите объект, правая кнопка → «Добавить в расширение».
  3. Для формы: добавьте форму в расширение, откройте её там, выделите элемент, в событии нажмите лупу. Конфигуратор спросит, как вызывать вашу процедуру относительно типовой: перед ней, после неё или вместо неё.
  4. Для модуля объекта: откройте модуль объекта в расширении и пометьте процедуру аннотацией.
&После("ПередЗаписью")
Процедура Расш1_ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
	// ваш код выполняется после типового обработчика
КонецПроцедуры

Доступные аннотации: &Перед, &После, &Вместо. С платформы 8.3.11 добавлена &ИзменениеИКонтроль — она позволяет поменять кусок типовой процедуры и предупредит, если после обновления типовой код изменится.

Префикс в имени процедур расширения (здесь Расш1_) задаётся в свойствах расширения. Он защищает от конфликта имён с типовыми процедурами.

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

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

Проверить, вызывается ли обработчик, проще всего точкой останова:

  1. Поставьте курсор на первую строку процедуры, нажмите F9.
  2. Запустите отладку F5.
  3. Выполните действие, которое должно вызвать событие.

Если отладчик не останавливается на серверном коде в клиент-серверной базе, проверьте, включена ли отладка на сервере 1С и подключён ли отладчик к серверным предметам отладки: меню Отладка → Подключение.

Диагностика: выберите симптом

Ещё две ошибки, которые не видны сразу:

  • 🐢 Тяжёлый код в клиентском обработчике. Запросы к базе внутри цикла по строкам на клиенте дают десятки серверных вызовов. Соберите данные и сделайте один вызов на сервер.
  • 🔁 Логика только в форме. Проверка в ПередЗаписьюНаСервере формы не сработает, если документ записывает обработка или обмен. Обязательные проверки держите в модуле объекта.

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

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