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