При разработке в среде 1С:Предприятие 8 часто возникает необходимость выполнить пакетную обработку документов, например, отправить их на печать. Традиционный подход с использованием оператора Цикл отлично работает в серверном контексте или старых обычных формах, однако в современных управляемых формах и веб-клиенте прямое ожидание ответа пользователя (например, через ПоказатьВопрос) невозможно. Код не «ждет» завершения диалога, а продолжает выполняться дальше, что приводит к нежелательным последствиям.
Давайте разберем, как правильно перестроить архитектуру кода, чтобы реализовать логику ожидания без использования устаревшей модальности.
Когда мы вызываем ПоказатьВопрос, платформа не приостанавливает выполнение текущей процедуры. Она лишь «регистрирует» вызов и сразу завершает выполнение текущего контекста, возвращая управление системе. Это сделано для того, чтобы не блокировать интерфейс, особенно в веб-браузере. Попытка организовать цикл внутри такой процедуры приведет к тому, что все итерации пройдут мгновенно, не дожидаясь нажатия кнопок пользователем.
Чтобы решить эту задачу, нам необходимо отказаться от императивного стиля «цикл — вопрос — продолжение» и перейти к событийной модели. Суть подхода заключается в том, что вместо цикла мы используем рекурсивный вызов процедуры, которая обрабатывает один документ за раз, а затем вызывает себя для следующего.
Разберем реализацию этого метода по шагам:
ОписаниеОповещения.Рассмотрим, как это выглядит на уровне программного кода. Мы создадим структуру параметров, которая позволит нам «помнить», на каком этапе обработки мы находимся.
&НаКлиенте
Процедура НачатьПечатьДокументов(Команда)
// Подготовим массив документов для печати
МассивДокументов = ПолучитьСписокДокументов();
СтруктураПараметров = Новый Структура;
СтруктураПараметров.Вставить("Список", МассивДокументов);
СтруктураПараметров.Вставить("Индекс", 0);
// Запускаем первую итерацию
ОбработатьСледующийДокумент(СтруктураПараметров);
КонецПроцедуры
&НаКлиенте
Процедура ОбработатьСледующийДокумент(Параметры)
Если Параметры.Индекс >= Параметры.Список.Количество() Тогда
Сообщить("Печать завершена!");
Возврат;
КонецЕсли;
// Печатаем текущий документ
ТекущийДокумент = Параметры.Список[Параметры.Индекс];
Печать(ТекущийДокумент);
// Проверяем, нужно ли прерваться для вопроса
Если НужноЗадатьВопрос(Параметры.Индекс) Тогда
Оповещение = Новый ОписаниеОповещения("ПослеОтветаПользователя", ЭтотОбъект, Параметры);
ПоказатьВопрос(Оповещение, "Печатаем следующий документ?", РежимДиалогаВопрос.ДаНет);
Иначе
// Продолжаем без вопроса
Параметры.Индекс = Параметры.Индекс + 1;
ОбработатьСледующийДокумент(Параметры);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПослеОтветаПользователя(Результат, Параметры) Экспорт
Если Результат = КодВозвратаДиалога.Да Тогда
Параметры.Индекс = Параметры.Индекс + 1;
ОбработатьСледующийДокумент(Параметры);
Иначе
Сообщить("Печать прервана пользователем.");
КонецЕсли;
КонецПроцедуры
Хранение состояния: Помните, что переменные цикла внутри процедуры исчезают при выходе из нее. Все необходимые данные (массив документов, текущий счетчик, настройки печати) нужно упаковывать в структуру и передавать через ОписаниеОповещения.
Подготовка данных: По возможности, старайтесь собрать все необходимые для печати данные до начала процесса. Это позволит избежать лишних вызовов сервера и сделает работу интерфейса более отзывчивой.
Отказ от модальности: Использование модальных окон в современных конфигурациях не рекомендуется. Даже если в настройках системы разрешено использование модальности, это может привести к невозможности работы в веб-клиенте. Рекомендуемый способ взаимодействия — именно асинхронные вызовы, которые мы разобрали выше.
Используя этот подход, вы сможете гибко управлять процессом печати, прерывать его, спрашивать подтверждение у пользователя и корректно возобновлять операцию без блокировки интерфейса всей системы.