Почему не работают события записи в управляемой форме при пометке на удаление в 1С и как это решить

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

В процессе разработки на платформе 1С:Предприятие 8 многие специалисты сталкиваются с неочевидным поведением системы: при установке или снятии пометки на удаление непосредственно из формы элемента (или документа) стандартные события записи формы — такие как ПередЗаписью, ПередЗаписьюНаСервере или ПриЗаписиНаСервере — попросту игнорируются. При этом аналогичные события в модуле самого объекта отрабатывают абсолютно штатно.

Давайте подробно разберем, почему платформа ведет себя именно так, что происходит с формой "под капотом" в этот момент, и как правильно реализовать бизнес-логику, если вам необходимо перехватить действие установки пометки на удаление.

Выясняем причину: почему платформа «обходит» события формы?

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

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

  1. Платформа напрямую обращается к объекту в базе данных (СУБД).
  2. Программно вызывается аналог метода УстановитьПометкуУдаления() на уровне сервера.
  3. Объект записывается непосредственно в базу данных, минуя весь цикл подготовки и сериализации данных, связанных с интерфейсом управляемой формы.

Поскольку классической интерактивной цепочки записи формы не происходит, события модуля управляемой формы (ПередЗаписью, ПередЗаписьюНаСервере, ПриЗаписиНаСервере, ПослеЗаписиНаСервере) вообще не запускаются. Данные формы не переносятся в объект на клиенте — запись сразу выполняется на уровне СУБД.

Что происходит с открытой формой после установки пометки?

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

Для этого платформа сразу после записи пометки в БД инициирует принудительное перечитывание (обновление) данных в форму. В этот момент выполняются следующие шаги:

  1. Вызывается стандартный механизм обновления данных формы из базы.
  2. Срабатывает событие формы ПриЧтенииНаСервере(ТекущийОбъект). В этот обработчик передается уже измененный объект из базы данных.
  3. Свойство формы Модифицированность принудительно сбрасывается в значение Ложь, так как данные формы теперь полностью синхронизированы с базой данных.

Подводные камни стандартных интерфейсных событий

Некоторые разработчики пытаются использовать событие таблицы или динамического списка ПередУстановкойПометкиУдаления. Однако здесь кроется серьезная ловушка.

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

Как правильно решить задачу: практические варианты

В зависимости от того, требуется ли вам участие пользователя (диалоги, вопросы) или же нужна только чистая бизнес-логика на сервере, рассмотрим два основных подхода.

Вариант А: Если нужна только серверная бизнес-логика (без интерактива)

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

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

Рассмотрим пример кода в модуле объекта:


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

Этот способ является максимально надежным, так как он гарантирует выполнение бизнес-логики независимо от того, как именно объект помечается на удаление: кнопкой из формы, групповой обработкой или через внешний API (например, интеграцию по REST).

Вариант Б: Если обязательно требуется интерактивный диалог с пользователем

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

Для реализации этого сценария выполним следующие шаги:

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

Проанализируем пример программной реализации такого подхода:

Код в модуле управляемой формы:


&НаКлиенте
Процедура КомандаПометитьНаУдаление(Команда)
    
    // Пример интерактивного вопроса пользователю
    ПараметрыОповещения = Новый ОписаниеОповещения("ПослеЗакрытияВопросаОПометке", ЭтотОбъект);
    ПоказатьВопрос(ПараметрыОповещения, "Вы действительно хотите пометить элемент на удаление и связанные с ним документы?", РежимДиалогаВопрос.ДаНет);
    
КонецПроцедуры

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

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

И в модуле объекта мы сможем легко перехватить этот вызов и выполнить специализированные проверки:


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

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

← На главную