Почему не срабатывает событие ПередЗаписью на форме в 1С при программном вызове записи?

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

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

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

Понимание архитектуры: Объект против Формы

Для того чтобы понять, почему событие не срабатывает, нам необходимо разграничить два понятия: Объект базы данных (например, ДокументОбъект) и Форма (визуальное представление этого объекта на клиенте).

Запись данных может происходить в двух разных контекстах:

  1. Интерактивно через форму: Пользователь нажимает кнопку "Записать" или "ОК". В этом случае платформа запускает полную цепочку событий экранной формы, проверяет модифицированность, заполнение реквизитов, выполняет обработчики формы ПередЗаписью, ПриЗаписи, и только затем передает управление в модуль самого объекта.
  2. Программно напрямую в базу данных: В коде вызывается метод Записать() самого объекта. При этом платформа работает напрямую с базой данных, полностью игнорируя интерфейсный слой (форму). Соответственно, события формы физически не могут быть вызваны, так как транзакция записи происходит вне контекста отображения.

Выясним причину, почему это происходит в различных типах форм, и как правильно написать код.

Решение для обычных форм (Толстый клиент)

В конфигурации УПП 1.3 большинство форм являются обычными. В модуле обычной формы вызов метода Записать() без явного указания контекста интерпретируется системой как обращение к самому прикладному объекту (то есть происходит неявный вызов ЭтотОбъект.Записать()).

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

Чтобы сымитировать интерактивное нажатие кнопки сохранения пользователем и запустить всю цепочку событий формы (включая проверку заполнения и событие формы ПередЗаписью), необходимо использовать специальный метод расширения формы — ЗаписатьВФорме().

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


// НЕПРАВИЛЬНО: события формы ПередЗаписью будут проигнорированы
Процедура ДействиеПриНажатииКнопки(Кнопка)
    // Изменяем реквизиты
    ЭтотОбъект.Комментарий = "Изменено программно";
    // Записываем напрямую объект
    ЭтотОбъект.Записать(); 
КонецПроцедуры

Рассмотрим правильный вариант вызова:


// ПРАВИЛЬНО: сработает вся цепочка событий формы
Процедура ДействиеПриНажатииКнопки(Кнопка)
    // Изменяем реквизиты
    ЭтотОбъект.Комментарий = "Изменено программно";
    // Вызываем метод формы для записи
    ЭтаФорма.ЗаписатьВФорме(); 
КонецПроцедуры

Использование метода ЗаписатьВФорме() гарантирует, что платформа отработает событие ПередЗаписью модуля формы, и если в нем будет установлен параметр Отказ = Истина, запись объекта в базу данных будет успешно заблокирована.

Решение для управляемых форм (Тонкий / Веб-клиент)

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


// НЕПРАВИЛЬНО: Запись на сервере вне контекста формы
&НаСервере
Процедура ЗаписатьОбъектНаСервере()
    // Конвертируем данные формы в физический объект
    ДокОбъект = РеквизитФормыВЗначение("Объект");
    ДокОбъект.Комментарий = "Обновлено на сервере";
    // Запись происходит на уровне СУБД, форма об этом не знает
    ДокОбъект.Записать(); 
    // Данные в форме на клиенте могут стать неактуальными
    ЗначениеВРеквизитФормы(ДокОбъект, "Объект");
КонецПроцедуры

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

Для корректной программной записи в управляемых формах следует вызывать метод формы Записать() на клиенте. Разберем по шагам правильную схему:


// ПРАВИЛЬНО: инициируем запись через клиентский контекст формы
&НаКлиенте
Процедура ВыполнитьСохранение()
    // Параметры записи формы (необязательно)
    ПараметрыЗаписи = Новый Структура;
    ПараметрыЗаписи.Вставить("РежимЗаписи", РежимЗаписиДокумента.Запись);
    
    // Вызов метода Записать() у самой формы
    РезультатЗаписи = ЭтаФорма.Записать(ПараметрыЗаписи);
КонецПроцедуры

При вызове метода ЭтаФорма.Записать() платформа автоматически запустит событие ПередЗаписью на клиенте, затем ПередЗаписьюНаСервере на сервере формы, и только после этого перейдет к транзакции записи самого объекта.

Проверка привязки обработчика в свойствах формы

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

Такое часто случается при переносе кода копированием или при обновлении конфигурации. Выполните следующие действия для проверки:

  1. Откройте форму объекта в конфигураторе.
  2. Перейдите в палитру свойств формы (нажмите правую кнопку мыши на форме -> Свойства).
  3. Найдите раздел События.
  4. Убедитесь, что в строке события ПередЗаписью (или Перед записью для обычных форм) указано имя вашей процедуры.
  5. Если поле пустое, выберите процедуру-обработчик из выпадающего списка или нажмите на кнопку с лупой для автоматического сопоставления.

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

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

Разберем, как им воспользоваться:

  1. В конфигураторе откройте меню Отладка -> Замер производительности (активируйте его перед выполнением действия).
  2. В режиме "1С:Предприятие" нажмите кнопку, которая вызывает вашу программную запись.
  3. Вернитесь в конфигуратор и отключите замер производительности через то же меню.
  4. Перед вами откроется таблица со всеми строками кода, которые физически выполнила платформа. Проанализируйте этот список: вы сразу увидите, заходила ли система в модуль формы и на каком этапе (возможно, из-за скрытого сбоя или досрочного возврата с флагом Отказ = Истина в модуле объекта) выполнение прекратилось.

Рекомендация по проектированию: перенос логики в модуль объекта

В сообщении 8 на форуме прозвучала важная архитектурная рекомендация: перенести критически важный функционал в модуль объекта.

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

Все жесткие бизнес-правила и проверки контроля данных должны располагаться в процедуре ПередЗаписью() модуля объекта. В модуле формы следует оставлять только интерактивные функции (например, вопросы пользователю "Вы уверены?", предупреждения, работу с визуальным оформлением элементов формы).

← На главную