Как в 1С 8.3 открыть форму и дождаться её закрытия для выполнения кода?

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

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

Причина отказа от модальности

Прежде чем мы разберем по шагам программный код, важно понять, почему метод «просто дождаться» больше не работает. Метод ОткрытьФормуМодально() блокирует выполнение всего программного кода на стороне клиента до тех пор, пока окно не будет закрыто. В браузере (веб-клиенте) такая блокировка невозможна или крайне нежелательна, так как она «вешает» поток выполнения скриптов. Именно поэтому 1С перешла к асинхронной модели работы через оповещения.

Решение 1: Использование ОписаниеОповещения (Классический подход)

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

Допустим, у нас есть процедура ВыполнитьМногоКодаНаФорме. Чтобы внедрить в неё открытие формы с ожиданием, нам нужно создать процедуру-обработчик.


&НаКлиенте
Процедура ОсновнаяКоманда(Команда)
    
    // Подготавливаем параметры для открытия
    ПараметрыОткрытия = Новый Структура;
    ПараметрыОткрытия.Вставить("Подразделение", Объект.ТекущееПодразделение);
    
    // Создаем описание оповещения. 
    // "ЗавершитьМоюОперацию" — это имя процедуры, которая выполнится ПОСЛЕ закрытия формы.
    // ЭтотОбъект — контекст, где искать эту процедуру.
    Оповещение = Новый ОписаниеОповещения("ЗавершитьМоюОперацию", ЭтотОбъект);
    
    // Открываем форму. 
    // Обратите внимание на предпоследний параметр (Оповещение) 
    // и последний (РежимОткрытияОкнаФормы.БлокироватьОкноВладельца)
    ОткрытьФорму("Документ.Заказ.Форма.ФормаПроверкиСкладов", 
                 ПараметрыОткрытия, 
                 ЭтотОбъект, 
                 ,,, 
                 Оповещение, 
                 РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);
                 
    // ВАЖНО: Весь код, который написан ниже этой строки, ВЫПОЛНИТСЯ СРАЗУ, 
    // не дожидаясь закрытия формы. Поэтому здесь кода быть не должно.
КонецПроцедуры

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

Решение 2: Заполнение формы перед открытием (ПолучитьФорму)

Иногда возникает вопрос: «Как мне не просто открыть форму, но и программно заполнить её данными перед показом пользователю, если я не могу менять код самой открываемой формы?». Выясним причину популярности метода ПолучитьФорму.

Если вы используете ОткрытьФорму, вы ограничены только передачей структуры Параметры. Если же вам нужно вызвать экспортные методы открываемой формы до её показа, используйте следующий подход:


&НаКлиенте
Процедура ОткрытьИЗаполнить(Команда)
    
    // 1. Получаем объект формы без её открытия
    МояФорма = ПолучитьФорму("Справочник.Номенклатура.Форма.ФормаВыбора", , ЭтотОбъект);
    
    // 2. Теперь мы можем обращаться к данным формы напрямую
    МояФорма.Объект.Комментарий = "Заполнено программно перед открытием";
    // Или вызвать её экспортный метод
    // МояФорма.ИнициализироватьСпецифическиеДанные(Объект.Ссылка);
    
    // 3. Назначаем оповещение о закрытии
    МояФорма.ОписаниеОповещенияОЗакрытии = Новый ОписаниеОповещения("ПослеЗакрытияМоейФормы", ЭтотОбъект);
    
    // 4. Открываем
    МояФорма.Открыть();
    
КонецПроцедуры

Решение 3: Современный метод Асинх / Ждать (платформа 8.3.18+)

Рассмотрим подробнее наиболее современный способ, который появился в последних релизах платформы. Он позволяет писать код практически линейно, избегая создания множества процедур-обработчиков — для этого подойдёт инструмент для ускорения отладки кода управляемых форм и асинхронных вызовов. Для этого используются ключевые слова Асинх и Ждать.

Хотя стандартный метод ОткрытьФорму пока не возвращает «обещание» напрямую, этот механизм уже работает для многих встроенных диалогов и может быть реализован через обертки. Посмотрим на пример с вопросом:


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

Как передать результат обратно в основную форму?

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

  1. В модуле открываемой формы (например, в обработчике нажатия кнопки «ОК»):
    
    &НаКлиенте
    Процедура КнопкаОК(Команда)
        РезультатВыбора = Новый Структура("Статус, Количество", Истина, 10);
        Закрыть(РезультатВыбора); // Передаем данные назад
    КонецПроцедуры
    
  2. В модуле вызывающей формы эти данные попадут в первый параметр процедуры оповещения:
    
    &НаКлиенте
    Процедура ЗавершитьМоюОперацию(Результат, ДополнительныеПараметры) Экспорт
        Если ТипЗнч(Результат) = Тип("Структура") И Результат.Статус Тогда
            Сообщить("Количество: " + Результат.Количество);
        КонецЕсли;
    КонецПроцедуры
    

Важные рекомендации по работе в облачных сервисах (1С:Фреш)

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

Третьим параметром в Новый ОписаниеОповещения можно передать структуру. Все данные, помещенные в неё, будут «живы» и доступны в процедуре завершения. Это позволяет не создавать лишние реквизиты формы для временного хранения промежуточных вычислений. Это делает ваш код чище и безопаснее с точки зрения производительности.

Подведем итог: Использование модальности — это пережиток прошлого. Правильный путь в 1С 8.3 — это разделение логики на «До открытия» и «После закрытия» с использованием ОписаниеОповещения. Это гарантирует стабильную работу вашей программы во всех режимах (тонкий клиент, веб-клиент, мобильный клиент).

← На главную