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