Как задать вопрос пользователю в управляемых формах 1С без модальных окон

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

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

Почему платформа запрещает остановку выполнения кода

В обычных формах вызов метода Вопрос() полностью останавливал выполнение текущего потока вплоть до получения ответа. Однако управляемый интерфейс ориентирован на работу в клиент-серверной архитектуре, веб-клиенте и мобильных приложениях. Браузерные технологии и специфика работы JavaScript не позволяют синхронно замораживать интерфейсный поток без риска блокировки всей страницы или потери соединения с сервером.

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

Подход 1: Разделение логики через описание оповещения

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

  1. Выполнение предварительных проверок.
  2. Отображение немодального диалога с вопросом.
  3. Обработка результата выбора пользователя в отдельной процедуре.

Посмотрим на практический пример реализации такой структуры:


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

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

&НаКлиенте
Процедура ВыполнитьПробитиеЧека()
    // Основной алгоритм проведения и фискализации
    ВыполнитьПробитиеНаСервере();
КонецПроцедуры

Такое разделение позволяет интерфейсу оставаться отзывчивым, при этом действие, зависящее от ответа, гарантированно не начнется до подтверждения диалога.

Подход 2: Линейный асинхронный код с оператором Ждать (начиная с 8.3.18)

Если конфигурация работает на современной платформе (версия 8.3.18 и выше), дробить код на отдельные процедуры с использованием объекта ОписаниеОповещения больше не обязательно. Платформа поддерживает ключевые слова Асинх и Ждать, позволяющие писать асинхронный код в линейном стиле, сохраняя привычную последовательность чтения.

Проанализируем пример использования асинхронного метода ВопросАсинх():


&НаКлиенте
Асинх Процедура КомандаПробитьЧек(Команда)
    // Предварительная проверка параметров
    Если Не ПроверитьЗаполнениеТабличнойЧасти() Тогда
        Возврат;
    КонецЕсли;

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

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

Блокировка интерфейса от случайных действий

Часто программисты опасаются, что кассир или оператор в процессе отображения немодального вопроса переключится на другое окно, собьет табличную часть или нажмет другие кнопки. Для предотвращения таких ситуаций стандартные методы ПоказатьВопрос и ВопросАсинх по умолчанию блокируют окно владельца всплывающим окном сообщения.

Если же для подтверждения вызывается отдельная сложная форма ввода данных (например, выбор причины отмены или дополнительный ввод веса), мы можем заблокировать родительские окна с помощью свойства открытия формы:


&НаКлиенте
Процедура ОткрытьФормуПодтверждения()
    ПараметрыФормы = Новый Структура;
    ПараметрыФормы.Вставить("РежимОткрытияОкнаФормы", РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);
    
    ОткрытьФорму("Обработка.РМК.Форма.ПодтверждениеСкидки", ПараметрыФормы, ЭтотОбъект);
КонецПроцедуры

Параметр БлокироватьОкноВладельца или БлокироватьВесьИнтерфейс гарантирует, что пользователь не сможет нажать кнопки в основном окне, пока не закроет всплывающее окно.

Паттерн обработки событий с параметром Отказ

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

Для таких случаев применяется паттерн с повторным вызовом действия и флагом состояния:

  1. Создаем переменную модуля формы (например, ДействиеПодтверждено = Ложь).
  2. В процедуре ПередЗакрытием или ПередУдалением проверяем флаг: если он равен Ложь, принудительно устанавливаем Отказ = Истина.
  3. Тут же вызываем асинхронный вопрос через ПоказатьВопрос или ВопросАсинх.
  4. В обработчике ответа, если пользователь согласился, устанавливаем ДействиеПодтверждено = Истина и повторно вызываем нужное программное действие (например, метод формы Закрыть() или программное удаление строки).
  5. При повторном срабатывании обработчика флаг равен Истина, проверка пропускается, операция успешно завершается.

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

← На главную