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