Перейти к содержимому

6.18 Где располагаются процедуры-обработчики событий прикладных объектов?

Опубликовано: Обновлено:

Telegram → Просто о платформе 1С

❓ 6.18 Где располагаются процедуры-обработчики событий прикладных объектов (например СправочникОбъект.<Имя справочника>), такие как ПередЗаписью, ПередУдалением?


Как разбирали в вопросе 6.16, для работы с отдельным объектом базы данных используются типы с постфиксом Объект.

Например, для справочника:

СправочникМенеджер.<Имя>
↓
СоздатьЭлемент()
↓
СправочникОбъект.<Имя>

СправочникОбъект.<Имя> позволяет работать с данными отдельного элемента справочника: изменять реквизиты, записывать и удалять объект.

Поведение отдельного экземпляра прикладного объекта описывается в модуле объекта.

Именно в нём располагаются процедуры-обработчики событий объекта:

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

Чтобы посмотреть, какие свойства, методы и события доступны для конкретного типа объекта, можно использовать Синтакс-помощник.

Для справочника нужно найти тип:

СправочникОбъект.<Имя справочника>

В описании типа отдельно перечислены его свойства, методы и события.

События типа СправочникОбъект в Синтакс-помощнике

Среди событий СправочникОбъект.<Имя справочника> находятся ОбработкаЗаполнения, ОбработкаПроверкиЗаполнения, ПередЗаписью, ПриЗаписи, ПередУдалением и другие.

События объекта и события формы — разные события.

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


ОбработкаЗаполнения предназначена для начального заполнения нового объекта.

Один из основных параметров обработчика — ДанныеЗаполнения.

Его значение зависит от того, каким способом создаётся объект.

Способ созданияДанныеЗаполнения
Обычное интерактивное создание (кнопка создать)Неопределено
Создание глобальной командойНеопределено
Создание на основанииссылка на объект-основание
Создание из списка с установленным отборомСтруктура со значениями отбора
Вызов метода Заполнить()Значение, переданное в параметр метода

Например, если новый объект создаётся из списка с отбором по поставщику и складу, в ДанныеЗаполнения будет передана структура со свойствами Поставщик и Склад.

Это позволяет в ОбработкаЗаполнения определить, откуда и каким способом создаётся объект, и выполнить необходимую логику заполнения.


Метод СоздатьЭлемент() или СоздатьДокумент() создаёт объект в памяти, но сам по себе не запускает механизм ОбработкаЗаполнения.

Например:

ОбъектНакладной = Документы.Накладная.СоздатьДокумент();

Если требуется программно запустить заполнение, используется метод Заполнить():

ЭлементыОтбора = Новый Структура(
"Поставщик, Дата",
СсылкаНаПоставщика,
ТекущаяДата());
ОбъектНакладной = Документы.Накладная.СоздатьДокумент();
ОбъектНакладной.Заполнить(ЭлементыОтбора);

В этом случае вызывается ОбработкаЗаполнения, а переданная структура поступает в параметр ДанныеЗаполнения.


Интерактивное создание и данные заполнения

Заголовок раздела «Интерактивное создание и данные заполнения»

Данные заполнения может сформировать и сама платформа.

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

Поставщик = ООО "Поставщик"
Склад = Основной

и создаёт новый документ.

Платформа передает значения такого отбора в ДанныеЗаполнения:

Список с отбором
↓
Создать
↓
ДанныеЗаполнения = Структура
↓
ОбработкаЗаполнения(...)

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


Программное открытие формы с данными заполнения

Заголовок раздела «Программное открытие формы с данными заполнения»

Такой же механизм можно использовать программно.

Для управляемой формы данные заполнения можно передать через параметр формы ЗначенияЗаполнения:

ЭлементыОтбора = Новый Структура(
"Поставщик, Склад",
СсылкаНаПоставщика,
СсылкаНаСклад);
ПараметрыФормы = Новый Структура(
"ЗначенияЗаполнения",
ЭлементыОтбора);
ОткрытьФорму(
"Документ.Накладная.ФормаОбъекта",
ПараметрыФормы);

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

Аналогичный принцип используется и при получении формы программно через ПолучитьФорму().


Свойства реквизитов, влияющие на начальное заполнение

Заголовок раздела «Свойства реквизитов, влияющие на начальное заполнение»

На начальное заполнение объекта влияют свойства реквизитов метаданных.

Значение заполнения

Позволяет платформе использовать одноимённое значение из ДанныеЗаполнения для автоматического заполнения реквизита.

Например, при создании объекта в ДанныеЗаполнения передано значение клиента:

ДанныеЗаполненияРеквизит объектаСвойство реквизитаРезультат
Клиент = СсылкаНаКлиентаКлиентЗаполнять из данных заполнения = ДаВ реквизит Клиент будет передано значение СсылкаНаКлиента

То есть платформа сопоставляет имя свойства в ДанныеЗаполнения с именем реквизита объекта и, если для реквизита разрешено «Заполнять из данных заполнения», использует переданное значение для его заполнения.

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


После вызова ОбработкаЗаполнения дальнейшее поведение зависит от параметра СтандартнаяОбработка.

Если он остаётся равным Истина, платформа продолжает стандартное заполнение.

Упрощённо:

Создание нового объекта
↓
Формирование ДанныеЗаполнения
↓
ОбработкаЗаполнения(...)
↓
СтандартнаяОбработка = Истина
↓
Реквизит уже заполнен?
┌─────────┴─────────┐
│ │
Да Нет
│ ↓
│ Для реквизита установлено
│ «Заполнять из данных заполнения»?
│ ┌─────┴─────┐
│ Нет Да
│ │ ↓
│ │ В ДанныеЗаполнения
│ │ есть значение
│ │ для этого реквизита?
│ │ ┌───┴───┐
│ │ Нет Да
│ │ │ ↓
│ │ │ Заполнение из
│ │ │ ДанныеЗаполнения
│ │ │
│ └────────┴───────┐
│ ↓
│ Реквизит заполнен?
│ ┌──────┴──────┐
│ Да Нет
│ │ ↓
│ │ Значение заполнения
│ │
└───────────────────────┴─────────────

То есть обработчик объекта может выполнить собственное заполнение, а затем платформа при включённой стандартной обработке дозаполняет реквизиты стандартными механизмами.

Если в обработчике установить:

СтандартнаяОбработка = Ложь;

дальнейшее стандартное заполнение платформой выполняться не будет.


Копирование объекта — отдельный сценарий

Заголовок раздела «Копирование объекта — отдельный сценарий»

Интерактивное создание объекта копированием обрабатывается отдельно.

Для этого существует событие:

ПриКопировании

Создать новый объект
│
├── обычное создание
│ ↓
│ ОбработкаЗаполнения
│
└── копирование
↓
ПриКопировании

В ПриКопировании передаётся копируемый объект.

При этом следует отдельно учитывать реквизиты типа ХранилищеЗначения: если такие данные необходимо перенести в новый объект, их копирование следует обрабатывать явно.


Следующий важный обработчик модуля объекта —

ОбработкаПроверкиЗаполнения.

Для реквизитов объектов существует свойство Проверка заполнения.

Если для реквизита требуется проверять заполненность, платформа формирует массив таких реквизитов и передаёт его в параметр:

ПроверяемыеРеквизиты.

Например:

Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
Если ОсобыйРежим Тогда
Индекс = ПроверяемыеРеквизиты.Найти("Комментарий");
Если Индекс <> Неопределено Тогда
ПроверяемыеРеквизиты.Удалить(Индекс);
КонецЕсли;
КонецЕсли;
КонецПроцедуры

В обработчике можно:

  • выполнить дополнительные проверки значений;
  • добавить реквизит в ПроверяемыеРеквизиты;
  • исключить реквизит из стандартной проверки;
  • самостоятельно выполнить проверку реквизита и после этого исключить его из дальнейшей стандартной проверки.

Это позволяет делать требование заполнения условным.

Например:

Обычный случай
↓
Реквизит проверяет платформа
Особый случай
↓
Проверку выполняет прикладной код
↓
Реквизит исключается
из ПроверяемыеРеквизиты

ОбработкаПроверкиЗаполнения выполняется вне транзакции записи объекта.


Программная запись и проверка заполнения

Заголовок раздела «Программная запись и проверка заполнения»

Следует учитывать важное отличие интерактивной и программной записи.

При программной записи:

Объект.Записать();

ОбработкаПроверкиЗаполнения автоматически не вызывается.

Если необходимо программно запустить механизм проверки заполнения объекта, используется:

Объект.ПроверитьЗаполнение();

Этот метод инициирует проверку заполнения объекта и вызов соответствующего обработчика модуля объекта.


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

При выполнении проверки заполнения последовательность упрощённо выглядит так:

ФОРМА                                   ОБЪЕКТ
  │                                        │
  │  ПередЗаписью                          │
  ↓                                        │
  │ ОбработкаПроверкиЗаполненияНаСервере   │
  ├───────────────────────────────────────→│
  │                                        │ ОбработкаПроверкиЗаполнения
  │                                        ↓
  │←───────────────────────────────────────┤
  │ ПередЗаписьюНаСервере                  │
  ↓                                        │
  │                                        │
  ├────── начало транзакции записи ────────┤
  │                                        │
  │                                        │ ПередЗаписью
  │                                        ↓
  │                                        │ (Запись объекта)
  │                                        ↓
  │                                        │ ПриЗаписи
  │                                        ↓
  │ ПриЗаписиНаСервере                     │
  ↓                                        │
  ├──── завершение транзакции записи ──────┤
  │                                        │
  │ ПослеЗаписиНаСервере                   │
  ↓                                        │
  │ ПослеЗаписи                            │
  ↓                                        │

Здесь хорошо видно различие между двумя уровнями:

МестоПримеры событий
Модуль формыПередЗаписью, ОбработкаПроверкиЗаполненияНаСервере, ПередЗаписьюНаСервере, ПриЗаписиНаСервере
Модуль объектаОбработкаПроверкиЗаполнения, ПередЗаписью, ПриЗаписи

ОбработкаПроверкиЗаполненияНаСервере относится к форме, а ОбработкаПроверкиЗаполнения — к самому прикладному объекту.


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

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

Например, значение реквизита можно сравнить с ранее записанным значением через Ссылка:

Если Ссылка.НоменклатурнаяГруппа <> НоменклатурнаяГруппа Тогда
// Номенклатурная группа была изменена.
КонецЕсли;
Ссылка.НоменклатурнаяГруппа → ранее записанное значение
НоменклатурнаяГруппа → новое значение объекта

Именно поэтому ПередЗаписью удобно использовать, когда необходимо определить, изменился ли реквизит объекта.


ПриЗаписи возникает после того, как данные объекта уже записаны в базу данных, но транзакция записи ещё не завершена.

Начало транзакции
↓
ПередЗаписью
↓
Запись объекта
↓
ПриЗаписи
↓
...
↓
Завершение транзакции

Таким образом:

ОбработчикСостояние записи
ОбработкаПроверкиЗаполненияНовое состояние ещё не записано, транзакция записи ещё не началась
ПередЗаписьюТранзакция уже началась, новое состояние ещё не записано
ПриЗаписиНовое состояние уже записано, транзакция ещё не завершена

Передача служебных параметров между обработчиками

Заголовок раздела «Передача служебных параметров между обработчиками»

Для передачи служебных параметров важно различать два сценария.

Если параметр необходимо передать из внешнего кода или из обработчика подписки на событие в обработчик модуля объекта, стандарт 1С рекомендует использовать свойство ДополнительныеСвойства.

📐 Стандарт разработки: #std639:2.1

Например, вызывающий код устанавливает служебный признак:

ФайлОбъект.ДополнительныеСвойства.Вставить(
"КонвертацияФайлов",
Истина);
ФайлОбъект.Записать();

А в модуле объекта этот признак можно проверить:

Процедура ПередЗаписью(Отказ)
Если ДополнительныеСвойства.Свойство("КонвертацияФайлов") Тогда
// Особая логика записи.
КонецЕсли;
КонецПроцедуры

То есть для передачи такого параметра не рекомендуется создавать экспортную переменную модуля объекта.


Между обработчиками одного модуля объекта

Заголовок раздела «Между обработчиками одного модуля объекта»

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

Ранее записанное значение можно получить через Ссылка. При этом, как разбирали в вопросе 6.15, если требуется получить отдельные реквизиты объекта, предпочтительнее использовать запрос.

Перем ПредыдущееЗначениеОрганизации;
Процедура ПередЗаписью(Отказ)
// Получаем ранее записанное значение Организации запросом.
ПредыдущееЗначениеОрганизации = ...;
КонецПроцедуры
Процедура ПриЗаписи(Отказ)
Если ПредыдущееЗначениеОрганизации <> Организация Тогда
// Значение реквизита Организация изменилось.
КонецЕсли;
КонецПроцедуры

Получается простое разделение:

Откуда и куда передаём данныеМеханизм
Из внешнего кода → в обработчики модуля объектаДополнительныеСвойства
Между обработчиками одного модуля объектаНеэкспортная переменная модуля объекта

Процедуры-обработчики событий прикладного объекта описываются в его модуле объекта.

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