В современных конфигурациях «1С:Предприятие» действует строгий запрет на использование модальных окон. Это связано с поддержкой веб-клиента, мобильных приложений и облачных сервисов (таких как 1С:Фреш), где блокировка выполнения потока инструкций недопустима на уровне браузеров и операционных систем. При попытке вызвать метод ОткрытьМодально() платформа генерирует исключение, если свойство конфигурации Режим использования модальности установлено в значение Не использовать.
Разберем типичную задачу: как открыть вспомогательную форму (например, диалог установки фильтров для фоновых заданий), дождаться действий пользователя, получить введенные значения и применить их в родительской форме без использования модальности.
---
При использовании устаревшего метода ОткрытьМодально() выполнение кода в вызывающей процедуре полностью приостанавливалось до момента закрытия диалога. Это позволяло писать линейный код:
// Устаревший синхронный подход
Диалог = ПолучитьФорму("Обработка.РегламентныеИФоновыеЗадания.Форма.ДиалогОтбораФоновогоЗадания", ПараметрыФормы);
Диалог.ОткрытьМодально();
// Следующая строка выполнялась ТОЛЬКО после закрытия окна
УстановитьОтборНаСервере(Новый ФиксированнаяСтруктура(Диалог.Отбор));
При переходе на немодальный вызов через ОткрытьФорму() окно открывается асинхронно. Код вызывающей процедуры продолжает выполняться мгновенно, не дожидаясь действий пользователя. В результате форма еще только отображается на экране, а программа уже пытается прочитать свойства закрытого или неинициализированного объекта, что приводит к получению значения Неопределено или ошибкам времени выполнения.
Для правильной организации работы необходимо разделить исходный алгоритм на две независимые части:
ОписаниеОповещения и открывает форму.---
Проанализируем классический подход, работающий во всех версиях платформы 1С 8.3 с управляемыми формами. Разберем по шагам код обеих форм.
В вызывающей форме создаем обработчик команды, формируем структуру параметров и связываем вызов с процедурой обратного вызова через ОписаниеОповещения.
&НаКлиенте
Процедура УстановитьОтбор(Команда)
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("Отбор", Новый Структура);
// Создаем описание процедуры, которая выполнится ПОСЛЕ закрытия диалога
ОповещениеОЗакрытии = Новый ОписаниеОповещения("ЗакрытиеФормыОтбора", ЭтаФорма);
// Внимание на синтаксис параметров метода ОткрытьФорму:
// 1 - ИмяФормы
// 2 - Параметры
// 3 - Владелец
// 4 - Уникальность
// 5 - Окно
// 6 - НавигационнаяСсылка
// 7 - ОписаниеОповещенияОЗакрытии
// 8 - РежимОткрытияОкна
ОткрытьФорму(
"Обработка.РегламентныеИФоновыеЗадания.Форма.ДиалогОтбораФоновогоЗадания",
ПараметрыФормы,
ЭтаФорма,
,
,
,
ОповещениеОЗакрытии,
РежимОткрытияОкнаФормы.БлокироватьОкноВладельца
);
КонецПроцедуры
Важный нюанс: частая ошибка разработчиков заключается в подсчете запятых при передаче параметров в метод ОткрытьФорму. Параметр ОписаниеОповещенияОЗакрытии является седьмым по счету. Если пропустить или добавить лишнюю запятую, платформа не выдаст синтаксической ошибки, однако обработчик закрытия никогда не вызовется.
В форме подбора или диалога отбора при нажатии кнопки «ОК» формируем структуру результата и передаем ее параметром в стандартную процедуру Закрыть().
&НаКлиенте
Процедура ОкЗакрытие(Команда)
// Формируем структуру параметров на клиенте или через вызов сервера
СтруктураОтбора = ПолучитьЗаполненныйОтбор();
// Передаем заполненную структуру в метод Закрыть
Закрыть(СтруктураОтбора);
КонецПроцедуры
&НаКлиенте
Функция ПолучитьЗаполненныйОтбор()
Отбор = Новый Структура;
Если ЗначениеЗаполнено(ОтборДатаНачала) Тогда
Отбор.Вставить("Начало", ОтборДатаНачала);
КонецЕсли;
Если ЗначениеЗаполнено(ОтборДатаОкончания) Тогда
Отбор.Вставить("Конец", ОтборДатаОкончания);
КонецЕсли;
Если ЗначениеЗаполнено(ОтборКлюч) Тогда
Отбор.Вставить("Ключ", ОтборКлюч);
КонецЕсли;
Если ЗначениеЗаполнено(ОтборНаименование) Тогда
Отбор.Вставить("Наименование", ОтборНаименование);
КонецЕсли;
Если ЗначениеЗаполнено(ОтборРегламентноеЗадание) Тогда
Отбор.Вставить("РегламентноеЗадание", ОтборРегламентноеЗадание);
КонецЕсли;
Возврат Отбор;
КонецФункции
В родительской форме объявляем экспортную клиентскую процедуру с обязательными параметрами Результат и ДополнительныеПараметры. Обязательно проверяем результат на Неопределено (на случай закрытия окна крестиком или клавишей Esc).
&НаКлиенте
Процедура ЗакрытиеФормыОтбора(Результат, ДополнительныеПараметры) Экспорт
// Пользователь закрыл окно без подтверждения (Esc / Крестик)
Если Результат = Неопределено Тогда
Возврат;
КонецЕсли;
// Передаем полученную структуру в серверную процедуру обработки
УстановитьОтборНаСервере(Новый ФиксированнаяСтруктура(Результат));
КонецПроцедуры
&НаСервере
Процедура УстановитьОтборНаСервере(ФиксОтбор)
Отбор = Новый Структура(ФиксОтбор);
ТаблицаФоновыеЗадания.Очистить();
Фоновые = ФоновыеЗадания.ПолучитьФоновыеЗадания(Отбор);
Для Каждого Фоновое Из Фоновые Цикл
НоваяСтрока = ТаблицаФоновыеЗадания.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, Фоновое);
КонецЦикла;
КонецПроцедуры
---
Начиная с версии платформы 8.3.18, в языке 1С появился механизм асинхронных функций, позволяющий избавиться от фрагментации кода и писать линейные алгоритмы без создания вспомогательных процедур оповещения.
Рассмотрим, как выглядит тот же функционал с использованием конструкции Асинх, Ждать и метода ОткрытьФормуАсинх:
&НаКлиенте
Асинх Процедура УстановитьОтбор(Команда)
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("Отбор", Новый Структура);
// Метод ОткрытьФормуАсинх ожидает закрытия формы и возвращает результат
Результат = Ждать ОткрытьФормуАсинх(
"Обработка.РегламентныеИФоновыеЗадания.Форма.ДиалогОтбораФоновогоЗадания",
ПараметрыФормы,
ЭтаФорма,
,
,
,
,
РежимОткрытияОкнаФормы.БлокироватьОкноВладельца
);
// Проверяем тип и корректность возвращенных данных
Если ТипЗнч(Результат) = Тип("Структура") Тогда
УстановитьОтборНаСервере(Новый ФиксированнаяСтруктура(Результат));
КонецЕсли;
КонецПроцедуры
Преимущество асинхронных методов — высокая читаемость и сохранение контекста локальных переменных внутри одной процедуры.
---
Если подчиненная форма проектируется как стандартная форма выбора, можно использовать механизм взаимодействия через события выбора:
Владелец = ЭтаФорма.ОповеститьОВыборе(СтруктураОтбора) и закрываем окно.ОбработкаВыбора:
&НаКлиенте
Процедура ОбработкаВыбора(ВыбранноеЗначение, ИсточникВыбора)
Если ТипЗнч(ВыбранноеЗначение) = Тип("Структура") Тогда
УстановитьОтборНаСервере(Новый ФиксированнаяСтруктура(ВыбранноеЗначение));
КонецЕсли;
КонецПроцедуры
---
Проанализируем, в каких ситуациях предпочтительнее применять каждый из рассмотренных подходов:
Использование правильных немодальных конструкций обеспечивает полную совместимость конфигурации с веб-клиентом, мобильной платформой и облачными сервисами без потери управляемости интерфейсом.