В современной практике разработки на платформе 1С:Предприятие 8.3 переход к асинхронным вызовам (отказ от модальности) стал обязательным стандартом. Одной из самых частых сложностей, с которой сталкиваются разработчики, является необходимость задать вопрос пользователю непосредственно перед записью или проведением документа. Проблема заключается в том, что стандартная кнопка Провести и закрыть перестает закрывать форму, если в событии ПередЗаписью выполнение прерывается для ожидания ответа пользователя. Разберем детально, почему это происходит и как элегантно решить эту задачу.
Давайте выясним, почему стандартное поведение формы нарушается. Когда пользователь нажимает кнопку Провести и закрыть, платформа запускает цепочку событий: ПередЗаписью -> ПриЗаписи -> ПослеЗаписи -> Закрытие формы. Если внутри ПередЗаписью мы устанавливаем Отказ = Истина, цепочка событий прерывается. Показать вопрос асинхронно мы можем только через ПоказатьВопрос, который не останавливает выполнение кода, а сразу передает управление дальше.
Чтобы дождаться ответа, мы вынуждены прервать запись, а затем, получив ответ в процедуре-оповещении, программно вызвать метод Записать(). Но здесь и кроется подвох: программный вызов метода Записать() — это уже новая команда, которая ничего не знает о том, что изначально пользователь хотел не просто записать документ, но и закрыть форму. Платформа «забывает» о намерении закрыть форму после прерывания первой попытки записи.
Рассмотрим наиболее правильный и современный способ решения. Начиная с определенных релизов платформы 8.3, в структуру ПараметрыЗаписи при нажатии стандартной кнопки Записать и закрыть (или Провести и закрыть) автоматически добавляется признак необходимости закрытия. Мы можем воспользоваться этим, передав этот флаг в наше оповещение. Проанализируем пример кода:
&НаКлиенте
Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
// Проверяем, не является ли это повторным входом после вопроса
Если ПараметрыЗаписи.Свойство("ВопросЗадан") Тогда
Возврат;
КонецЕсли;
// Условие, при котором нужно задать вопрос
Если ПараметрыЗаписи.РежимЗаписи = РежимЗаписиДокумента.Проведение
И Объект.Оплачено Тогда
// Прерываем текущую запись
Отказ = Истина;
// Запоминаем, нужно ли нам закрывать форму
НужноЗакрыть = Ложь;
ПараметрыЗаписи.Свойство("ЗаписатьИЗакрыть", НужноЗакрыть);
// Формируем дополнительные параметры для оповещения
ДопПараметры = Новый Структура;
ДопПараметры.Вставить("ПараметрыЗаписи", ПараметрыЗаписи);
ДопПараметры.Вставить("НужноЗакрыть", НужноЗакрыть);
ОписаниеОповещения = Новый ОписаниеОповещения("ПослеВопросаОбАннулировании", ЭтотОбъект, ДопПараметры);
ПоказатьВопрос(ОписаниеОповещения, "Аннулировать связанную заявку?", РежимДиалогаВопрос.ДаНет);
КонецЕсли;
КонецПроцедуры
Теперь разберем, что происходит в обработчике завершения. Нам нужно не только установить реквизиты объекта, но и повторно инициировать запись, передав флаг, предотвращающий зацикливание, и при необходимости закрыть форму.
&НаКлиенте
Процедура ПослеВопросаОбАннулировании(Результат, ДопПараметры) Экспорт
Если Результат = КодВозвратаДиалога.Да Тогда
Объект.АннулироватьЗаявку = Истина;
Иначе
Объект.АннулироватьЗаявку = Ложь;
КонецЕсли;
// Добавляем флаг, чтобы повторно не зайти в условие вопроса
ПараметрыЗаписи = ДопПараметры.ПараметрыЗаписи;
ПараметрыЗаписи.Вставить("ВопросЗадан", Истина);
// Выполняем запись
Если Записать(ПараметрыЗаписи) И ДопПараметры.НужноЗакрыть Тогда
Закрыть();
КонецЕсли;
КонецПроцедуры
Если по каким-то причинам работа со структурой ПараметрыЗаписи кажется неудобной, мы можем использовать переменную модуля формы для хранения состояния. Это классический подход, рекомендованный в материалах ИТС. Разберем его по шагам:
РазрешитьЗапись в начале модуля формы.ПередЗаписью проверяем значение этой переменной.Ложь, отменяем запись и выводим вопрос.Истина и вызываем Записать().Важный момент: Чтобы форма закрылась, при повторном вызове Записать() необходимо понимать контекст. Если мы используем свои кнопки, мы можем управлять этим процессом напрямую.
Иногда проще заменить стандартные кнопки формы на собственные команды. Это дает полный контроль над логикой закрытия. Однако возникает вопрос сохранения привычного пользователю интерфейса (горячих клавиш). Посмотрим на настройки кнопок:
Для команды, которая должна имитировать поведение Провести и закрыть, в свойствах кнопки на форме можно установить свойство КнопкаПоУмолчанию в значение Авто или Да. В ОС Windows это автоматически привязывает клавиши Ctrl + Enter к этой кнопке. Таким образом, пользователь не заметит подмены, а вы получите чистый код без прерываний стандартных обработчиков.
Если ваша конфигурация разработана на базе Библиотеки стандартных подсистем (БСП), мы рекомендуем обратить внимание на механизм Подключаемый_ПередЗаписью. БСП предоставляет развитый инструментарий для работы с вопросами пользователю. Использование общих процедур типа ОбщегоНазначенияКлиент.ПоказатьВопросПользователю позволяет сохранять контекст выполнения более надежно, так как библиотека берет на часть рутинных проверок параметров записи на себя.
В завершение отметим, что при программном вызове Записать(ПараметрыЗаписи) после ответа на вопрос, важно убедиться, что в ПараметрыЗаписи переданы верные РежимЗаписи и РежимПроведения, чтобы документ не просто записался, а именно провелся, как и предполагалось изначально.