Как корректно определить, нужно ли закрывать форму после выполнения асинхронного вопроса в ПередЗаписью?

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

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

Почему стандартный механизм не справляется?

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

Решение 1: Замена стандартных команд собственными

Это самый надежный архитектурный подход. Вместо использования стандартных кнопок «Записать» и «Записать и закрыть» мы создаем свои команды, которые передают нужный нам признак через параметры.

Выполним это по шагам:

  1. Создадим на форме две новые команды: МояЗапись и МояЗаписьИЗакрыть.
  2. В обработчике команды МояЗаписьИЗакрыть будем вызывать процедуру записи, передавая структуру с флагом закрытия.

&НаКлиенте
Процедура МояЗаписьИЗакрыть(Команда)
    СтруктураПараметров = Новый Структура;
    СтруктураПараметров.Вставить("ЗакрытьПослеЗаписи", Истина);
    Записать(СтруктураПараметров);
КонецПроцедуры

Теперь в ПередЗаписью() мы сможем прочитать этот флаг из объекта ПараметрыЗаписи:


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

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

Решение 2: Использование переменных модуля формы для отслеживания состояния

Если менять кнопки нежелательно, можно попробовать реализовать механизм «костылей» через переменные модуля формы, однако этот метод требует осторожности при использовании событий формы.

Рассмотрим пример использования переменной ВыполняетсяЗакрытие:


&НаКлиенте
Перем ВыполняетсяЗакрытие;

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

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

Ключевые рекомендации

При реализации любого из предложенных вариантов важно помнить следующие правила:

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

← На главную