Как заменить модальную функцию Вопрос() на немодальные вызовы при отключенной модальности в 1С

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

В современных конфигурациях 1С:Предприятие 8.3 разработчики всё чаще сталкиваются с запретом на использование модальных окон. Это связано с развитием веб-клиента и требованиями к кроссплатформенности. Когда в свойствах конфигурации режим использования модальности установлен в значение Не использовать, привычная функция Вопрос() начинает вызывать ошибки выполнения. Разберем подробно, как переписать код, чтобы сохранить логику взаимодействия с пользователем, используя методы ПоказатьВопрос() и ВопросАсинх().

В чем главная сложность перехода?

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


Ответ = Вопрос("Сохранить изменения?", РежимДиалогаВопрос.ДаНет);
Если Ответ = КодВозвратаДиалога.Да Тогда
    // Код сохранения
КонецЕсли;
// Продолжение кода

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

Решение №1: Использование метода ПоказатьВопрос() и ОписаниеОповещения

Этот метод является классическим для версий платформы ниже 8.3.18, но остается актуальным и сегодня. Основная идея заключается в разделении одной процедуры на две части: ту, что задает вопрос, и ту, что обрабатывает ответ. Разберем по шагам, как это реализовать.

Сначала мы создаем объект ОписаниеОповещения, который указывает системе, какую процедуру нужно вызвать после того, как пользователь нажмет на кнопку в диалоге. Рассмотрим пример переработки кода:


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

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

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

Решение №2: Использование современного метода ВопросАсинх()

Начиная с версии платформы 8.3.18, 1С ввела механизм асинхронных вызовов, который визуально гораздо ближе к старому способу написания кода. Рассмотрим, как это выглядит. Выясним причину популярности этого метода: он позволяет избежать «разрывания» кода на несколько процедур.

Чтобы использовать этот подход, сама процедура должна быть помечена ключевым словом Асинх, а перед вызовом функции ставится оператор Ждать.


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

Проанализируем ситуацию: метод ВопросАсинх() возвращает Обещание, которое оператор Ждать превращает в конкретное значение КодВозвратаДиалога. Это значительно упрощает чтение кода.

Решение №3: Автоматический рефакторинг средствами Конфигуратора

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

  1. Откройте модуль в режиме Конфигуратора.
  2. Найдите строку с вызовом функции Вопрос().
  3. Нажмите на ней правой кнопкой мыши.
  4. Выберите пункт меню Рефакторинг.
  5. Далее выберите Нерекомендуемые синхронные вызовы —> Преобразовать вызов.

Система сама предложит создать процедуру-обработчик и сформирует структуру ОписаниеОповещения. Однако будьте внимательны: после автоматического рефакторинга всегда стоит проверить корректность передачи контекста (локальных переменных) через ДополнительныеПараметры, особенно если вызов находился внутри сложного цикла или условия.

Особые случаи: События «ПередЗаписью» и «ПередЗакрытием»

Наибольшую трудность вызывает использование вопросов в предопределенных событиях, таких как ПередЗаписью(). Проблема в том, что эти события ожидают немедленного заполнения параметра Отказ.

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

  1. В процедуре ПередЗаписью() мы проверяем наличие некоего «флага подтверждения» (например, переменной модуля формы).
  2. Если флаг не установлен, мы устанавливаем Отказ = Истина и вызываем ПоказатьВопрос().
  3. В обработчике ответа, если пользователь согласился, мы устанавливаем флаг в Истина и программно вызываем метод Записать().
  4. При повторном входе в ПередЗаписью() система видит флаг, не задает вопрос и пропускает запись дальше.

Резюмируем: переход на немодальность — это не просто замена имен функций. Это изменение структуры кода в сторону событийной модели или использование современного синтаксиса Асинх/Ждать. Выбор метода зависит от версии вашей платформы и сложности текущего алгоритма.

← На главную