Как задать вопрос пользователю перед открытием внешней обработки в 1С

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

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

Проблема асинхронного вызова в управляемых формах

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

Рассмотрим основной способ решения этой задачи, который заключается в «двойном» вызове события открытия с использованием управляющего флага (переменной состояния).

Способ 1: Использование переменной-флага и повторного открытия

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

Выполним следующие шаги:

  1. Объявим переменную на клиенте в самом верху модуля формы.
  2. В процедуре ПриОткрытии пропишем логику анализа этой переменной.
  3. Создадим процедуру-обработчик оповещения для обработки ответа пользователя.

Посмотрим на пример кода:


&НаКлиенте
Перем ПроверкаПройдена;

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

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

Разберем ситуацию подробнее. Когда пользователь запускает обработку, срабатывает ПриОткрытии. Так как ПроверкаПройдена еще не определена, параметр Отказ устанавливается в Истина, и форма закрывается, не успев отрисоваться. Одновременно на экран выводится вопрос. Когда пользователь нажимает «Да», вызывается процедура ПослеОтветаНаВопрос, флаг меняется на Истина, и метод ЭтаФорма.Открыть() инициирует повторный вход в ПриОткрытии. На этот раз условие Отказ = Истина не выполняется, и форма открывается штатно.

Способ 2: Открытие формы и мгновенное закрытие

Если вам не критично кратковременное «мелькание» формы (хотя на быстрых компьютерах оно почти незаметно), можно использовать более простой подход. Мы позволяем форме открыться, сразу показываем вопрос, и если пользователь отказывается — закрываем форму программно.

Проанализируем пример реализации:


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

&НаКлиенте
Процедура ПроверитьОтветПользователя(Результат, Параметры) Экспорт
    
    Если Результат <> КодВозвратаДиалога.Да Тогда
        Закрыть(); // Закрываем уже открытую форму
    КонецЕсли;
    
КонецПроцедуры

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

Способ 3: Использование «формы-заставки» (наиболее профессиональный)

Для сложных внешних обработок рекомендуется создать две формы: основную и вспомогательную (диалоговую). Вспомогательная форма настраивается как форма по умолчанию. Она содержит только текст предупреждения и кнопки «Запустить» и «Отмена».

Выясним преимущества этого метода:

Алгоритм действий в коде вспомогательной формы:


&НаКлиенте
Процедура КнопкаЗапуститьНажата(Команда)
    // Открываем основную форму обработки
    ОткрытьФорму("ВнешняяОбработка.ИмяВашейОбработки.Форма.ОсновнаяФорма");
    // Закрываем текущую форму вопроса
    Закрыть();
КонецПроцедуры

Рекомендации по оптимизации

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

Рассмотрим подробнее: мы можем передать в ОткрытьФорму структуру параметров, в которой будет ключ ПроверкаПройдена. В серверном обработчике ПриСозданииНаСервере проверяйте наличие этого параметра. Если его нет — не загружайте тяжелые данные, так как форма все равно будет закрыта через Отказ = Истина в клиентской процедуре ПриОткрытии.

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

← На главную