Почему форма 1С не закрывается после нажатия «Провести и закрыть» при использовании диалогов в «ПередЗаписью»?

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

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

Выясним причину: куда пропадает команда закрытия?

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

Если в процедуре ПередЗаписью вы вызываете диалоговое окно, выполнение кода прерывается. Чтобы показать вопрос и дождаться ответа, вы устанавливаете Отказ = Истина, тем самым отменяя текущую (стандартную) итерацию записи. После того как пользователь нажимает «Да» в вашем окне, вы программно вызываете метод Записать(ПараметрыЗаписи).

В чем заключается ошибка: при повторном вызове метода Записать из обработчика оповещения (после ответа на вопрос), платформа часто «теряет» тот самый контекст интерактивного нажатия кнопки. Если вы просто передаете ПараметрыЗаписи без предварительной подготовки или вызываете метод без параметров, система воспринимает это как обычную команду «Записать», а не «Записать и закрыть».

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

Решение №1: Использование структуры ПараметрыЗаписи и флага-предохранителя

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

  1. В процедуре ПередЗаписью проверяем, не задавали ли мы вопрос ранее.
  2. Если нет — отменяем запись и вызываем диалог.
  3. В структуру параметров добавляем свой флаг (например, "ВопросЗадан").
  4. В обработчике оповещения вызываем Записать, передавая дополненную структуру параметров.

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


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

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

В данном примере крайне важно, что мы передаем ДополнительныеПараметры (которые на самом деле являются структурой ПараметрыЗаписи из исходной процедуры) обратно в метод Записать(). Именно в этой структуре «живет» информация о том, что была нажата кнопка «Провести и закрыть».

Решение №2: Использование механизмов БСП (для типовых конфигураций)

Если вы работаете в современной конфигурации на базе БСП (например, УТ 11, ERP, БП 3.0), рекомендуется использовать штатные механизмы обработки записи. В типовых решениях часто предусмотрены процедуры-обработчики, которые позволяют вклиниться в процесс записи более элегантно.

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

Рассмотрим структуру параметров, которую ожидает система при вызове записи объекта:


ПараметрыЗаписи = Новый Структура;
ПараметрыЗаписи.Вставить("РежимЗаписи", РежимЗаписиДокумента.Проведение);
ПараметрыЗаписи.Вставить("ЗаписыватьВладельца", Истина);
// Если мы хотим, чтобы форма закрылась, платформа должна видеть признак закрытия
// В некоторых версиях БСП это свойство называется явно:
ПараметрыЗаписи.Вставить("Закрыть", Истина);

Если вы вручную формируете такую структуру и передаете её в ЭтотОбъект.Записать(ПараметрыЗаписи), форма закроется корректно. Однако помните, что при обычном нажатии на кнопку «Записать» (без закрытия) этот флаг будет лишним. Поэтому самый надежный способ — это перехват и сохранение системных параметров, как показано в Решении №1.

Важные нюансы при работе с расширениями

При использовании расширений и аннотации &Перед, ситуация усложняется. Если вы в расширении устанавливаете Отказ = Истина, основной код формы может вообще не выполниться.

Проанализируем риски: если в основной конфигурации в процедуре ПередЗаписью уже реализована какая-то важная логика (например, замеры производительности, как упоминалось в сообщении №2 форума), ваша отмена записи в расширении предотвратит выполнение этого кода. Поэтому, если ваша задача — просто вывести вопрос, убедитесь, что после ответа «Да» вы действительно инициируете полную цепочку событий записи.

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

Почему закрывается только со второго раза? (Резюме)

Подведем итог. Причина «двойного клика» кроется в следующем:

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

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

← На главную