Модальность в 1С:Предприятии 8.3: как окна блокируют интерфейс и чем их заменить
Содержание
Частое заблуждение: модальное окно в 1С «вешает базу» и мешает работать другим пользователям. Это не так. Модальное окно блокирует только интерфейс того сеанса, где его открыли: пока вы не ответите на вопрос или не закроете форму, остальные окна программы у вас не реагируют. Сервер и чужие сеансы продолжают работать.
Для разработчика модальность — это ещё и вопрос архитектуры. В платформе 8.3 у конфигурации есть свойство Режим использования модальности. В типовых конфигурациях на управляемых формах оно стоит в значении «Не использовать», и синхронные вызовы вроде Вопрос() или ОткрытьМодально() там вызывают ошибку. Ниже — как это устроено, чем отличается от обычных окон и как настроить поведение под свою задачу.
Как работает модальное окно в 1С и что именно оно блокирует
Модальное окно — это форма или диалог, который перехватывает ввод пользователя. Пока он открыт, нельзя переключиться на другие окна программы, нажать команду в панели разделов или закрыть основное окно.
В классическом (синхронном) варианте модальность работает и на уровне кода. Встроенный язык останавливается на строке вызова и ждёт, пока пользователь ответит:
Ответ = Вопрос("Провести документ?", РежимДиалогаВопрос.ДаНет);
Если Ответ = КодВозвратаДиалога.Да Тогда
Записать(Новый Структура("РежимЗаписи", РежимЗаписиДокумента.Проведение));
КонецЕсли;
Здесь выполнение процедуры замирает на Вопрос(). Следующая строка выполнится только после нажатия «Да» или «Нет».
Что блокируется, а что нет:
- 🔒 Блокируется: ввод во все остальные окна клиентского приложения текущего сеанса.
- 🔒 Блокируется: выполнение кода процедуры, которая вызвала синхронный диалог.
- ✅ Не блокируется: сервер 1С, фоновые и регламентные задания.
- ✅ Не блокируется: работа других пользователей, в том числе с теми же документами.
- ✅ Не блокируется: обработчики ожидания, подключённые через
ПодключитьОбработчикОжидания(), — они продолжают срабатывать в клиентском приложении.
Модальность — свойство клиентской части. Транзакция на сервере не может «висеть» в ожидании ответа пользователя: серверный вызов завершается до того, как клиент покажет окно.
Режимы открытия формы и способы её вызвать
У управляемой формы есть свойство РежимОткрытияОкна. Его задают в конфигураторе в палитре свойств формы или передают параметром в ОткрытьФорму(). Значений три.
| Значение | Что блокирует | Типичное применение |
|---|---|---|
Независимый | Ничего | Списки, документы, отчёты |
БлокироватьОкноВладельца | Только окно-владелец | Форма подбора, ввод реквизитов строки |
БлокироватьВесьИнтерфейс | Все окна приложения | Обязательный выбор перед продолжением |
Режим БлокироватьОкноВладельца удобен тем, что пользователь видит, к какой форме относится диалог, и может работать с другими окнами. Окно-владелец задают третьим параметром ОткрытьФорму(), обычно это ЭтотОбъект.
Синхронный и асинхронный вызов
Важно различать две вещи: окно, которое блокирует интерфейс, и код, который ждёт ответа. Блокирующее окно можно открыть асинхронно — тогда интерфейс заблокирован, а код идёт дальше.
Синхронные методы (работают только при разрешённой модальности):
Вопрос(),Предупреждение();ВвестиЗначение(),ВвестиЧисло(),ВвестиСтроку(),ВвестиДату();ОткрытьФормуМодально()и метод формыОткрытьМодально().
Асинхронные аналоги:
ПоказатьВопрос(),ПоказатьПредупреждение();ПоказатьВводЗначения(),ПоказатьВводЧисла(),ПоказатьВводСтроки(),ПоказатьВводДаты();ОткрытьФорму()с параметромОписаниеОповещенияОЗакрытии.
Асинхронный вызов получает объект ОписаниеОповещения. В нём указано имя экспортной процедуры, которую платформа вызовет после закрытия окна:
&НаКлиенте
Процедура Провести(Команда)
Оповещение = Новый ОписаниеОповещения("ПослеОтветаНаВопрос", ЭтотОбъект);
ПоказатьВопрос(Оповещение, "Провести документ?", РежимДиалогаВопрос.ДаНет);
КонецПроцедуры
&НаКлиенте
Процедура ПослеОтветаНаВопрос(Результат, ДополнительныеПараметры) Экспорт
Если Результат = КодВозвратаДиалога.Да Тогда
Записать(Новый Структура("РежимЗаписи", РежимЗаписиДокумента.Проведение));
КонецЕсли;
КонецПроцедуры
Своя форма возвращает результат так же: внутри неё вызывают Закрыть(Значение), и это значение приходит в первый параметр процедуры-оповещения.
Где модальные окна встречаются в типовых конфигурациях
В «Бухгалтерии предприятия» 3.0, ЗУП 3.1 и «Управлении торговлей» 11 модальность в конфигурации отключена. Но окна, которые блокируют интерфейс, пользователи видят постоянно — они открыты асинхронно.
Типичные случаи:
- ❓ вопрос при закрытии формы с несохранёнными изменениями: «Данные были изменены. Сохранить изменения?»;
- 📋 формы подбора номенклатуры в табличную часть документа;
- 📅 выбор периода отчёта;
- 🗂️ формы выбора из справочника при нажатии кнопки выбора в поле;
- ⚙️ формы настройки печати и параметров обработок;
- 🔐 запрос пароля или подтверждения при подписании документов электронной подписью.
Модальные вызовы в коде остаются в старых внешних обработках, в доработках, написанных под 8.2, и в конфигурациях на обычных формах. Именно они дают ошибку после переноса в базу с отключённой модальностью.
Внешняя обработка с вызовом Вопрос() или Предупреждение() в типовой БП 3.0 упадёт с сообщением Использование модальных окон в данном режиме запрещено!. Код нужно переписать на асинхронные методы — менять свойство типовой конфигурации ради одной обработки не стоит.
Модальное окно, независимая форма и закладки: в чём разница
Путаница возникает из-за того, что «окно» в 1С значит разное в зависимости от интерфейса.
Независимая форма. Открывается в основном окне программы или отдельным окном. Можно держать открытыми десятки таких форм и переключаться между ними.
Закладки и отдельные окна. В интерфейсе «Такси» формы по умолчанию открываются в рабочей области основного окна, а список открытых форм виден на панели открытых. Пользователь может переключить режим на отдельные окна в параметрах программы (Главное меню → Сервис → Параметры). Это аналог старого MDI-подхода: много дочерних окон внутри одного приложения. На модальность настройка не влияет.
Блокирующая форма. Открывается поверх, отдельным плавающим окном. Пока она открыта, окно-владелец или весь интерфейс недоступны.
| Признак | Независимая | Блокирует владельца | Блокирует весь интерфейс |
|---|---|---|---|
| Можно переключиться на другую форму | Да | Да, кроме владельца | Нет |
| Отображение | В рабочей области или отдельно | Плавающее окно | Плавающее окно |
| Ждёт ли код ответа | Нет | Только при синхронном вызове | Только при синхронном вызове |
| Работает в веб-клиенте | Да | Да | Да |
Последняя строка часто удивляет. Веб-клиент не умеет синхронно останавливать код, пока пользователь отвечает: браузер не даёт так делать. Поэтому отключение модальности касается именно синхронных методов, а не самих блокирующих окон.
Зависания, «потерянные» диалоги и блокировки данных
Пользователь говорит «1С зависла». Нередко причина — модальное окно, которое оказалось за основным окном или на втором мониторе.
Как это распознать:
- Программа не реагирует на клики, но курсор не крутится и загрузка процессора нормальная.
- На панели задач Windows у значка 1С есть второе окно.
- После
Alt+Tabили клика по значку на панели задач появляется диалог с вопросом.
Ответ на вопрос или закрытие диалога сразу возвращает управление.
Модальность и блокировка объекта — разные вещи
Когда пользователь начал редактировать документ, платформа ставит пессимистическую блокировку объекта. Второй пользователь получит сообщение, что объект уже редактируется. Это не модальность: блокировка держится, пока форма объекта открыта и изменена, неважно, открыт ли поверх неё диалог.
Здесь модальность косвенно вредит. Пользователь начал менять документ, получил вопрос, ушёл на обед. Документ заблокирован для коллег всё это время. Решение организационное: закрывать формы, а не бросать их с открытыми диалогами.
Производительность
Сам по себе блокирующий диалог ресурсов не ест. Проблемы дают другие сценарии:
- 🐢 серверный вызов в цикле с показом вопроса на каждой итерации — каждый раз лишний обмен клиент-сервер;
- 🐢 тяжёлая форма подбора, которая при открытии читает весь справочник;
- 🐢 вопрос внутри обработчика ожидания, срабатывающего каждые несколько секунд, — диалоги копятся.
Как настроить режим использования модальности
Свойство конфигурации
Откройте конфигуратор, в дереве конфигурации вызовите свойства корневого элемента и найдите раздел совместимости. Свойство Режим использования модальности принимает три значения:
| Значение | Поведение синхронных методов |
|---|---|
| Использовать | Работают как раньше |
| Использовать с предупреждениями | Работают, но платформа выдаёт предупреждения о вызове |
| Не использовать | Вызов завершается ошибкой |
Свойство появилось в платформе 8.3.3. Для новых конфигураций по умолчанию стоит «Не использовать». Рядом есть похожее свойство Режим использования синхронных вызовов расширений платформы и внешних компонент — оно управляет методами работы с файлами и внешними компонентами, например синхронными диалогами выбора файла.
Не меняйте эти свойства в типовой конфигурации на поддержке: это снимет её с полной поддержки по свойствам и усложнит обновление.
Найти модальные вызовы в своей доработке
В конфигураторе есть два инструмента:
Конфигурация → Проверка конфигурации— в настройках проверки отметьте поиск использования модальности. Список строк с синхронными вызовами появится в окне сообщений.- Меню
Конфигурация → Рефакторингсодержит команды поиска и преобразования модальных вызовов. Автоматическое преобразование переписывает простые случаи наПоказатьВопрос()с процедурой-оповещением.
После автоматического преобразования перечитайте код. Если после вопроса шёл код, который не должен выполняться до ответа, рефакторинг переносит его в оповещение, но вложенные циклы и условия иногда требуют ручной правки.
Асинх и Ждать вместо цепочек оповещений
С платформы 8.3.18 есть асинхронные функции. Процедуру помечают словом Асинх, а вызов — оператором Ждать. Код снова читается сверху вниз, но интерфейс не блокируется синхронно:
&НаКлиенте
Асинх Процедура Провести(Команда)
Ответ = Ждать ВопросАсинх("Провести документ?", РежимДиалогаВопрос.ДаНет);
Если Ответ = КодВозвратаДиалога.Да Тогда
Записать(Новый Структура("РежимЗаписи", РежимЗаписиДокумента.Проведение));
КонецЕсли;
КонецПроцедуры
Такой код работает при модальности «Не использовать». Для старых релизов платформы и режима совместимости ниже 8.3.18 остаётся вариант с ОписаниеОповещения.
Вопрос в обработчиках «Перед записью» и «Перед закрытием»
Это главный приём, без которого переход на асинхронность не получается. Обработчик ПередЗаписью формы должен вернуть Отказ сразу, ответа ждать он не может. Схема такая:
- При первом вызове ставим
Отказ = Истинаи показываемПоказатьВопрос(). - В процедуре-оповещении при ответе «Да» поднимаем флаг-реквизит формы, например
ЗаписьПодтверждена. - Снова вызываем
Записать(). - В
ПередЗаписьювидим флаг, сбрасываем его и пропускаем вопрос.
&НаКлиенте
Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
Если ЗаписьПодтверждена Тогда
ЗаписьПодтверждена = Ложь;
Возврат;
КонецЕсли;
Отказ = Истина;
Оповещение = Новый ОписаниеОповещения("ПослеПодтвержденияЗаписи", ЭтотОбъект, ПараметрыЗаписи);
ПоказатьВопрос(Оповещение, "Записать изменения?", РежимДиалогаВопрос.ДаНет);
КонецПроцедуры
&НаКлиенте
Процедура ПослеПодтвержденияЗаписи(Результат, ПараметрыЗаписи) Экспорт
Если Результат = КодВозвратаДиалога.Да Тогда
ЗаписьПодтверждена = Истина;
Записать(ПараметрыЗаписи);
КонецЕсли;
КонецПроцедуры
ЗаписьПодтверждена — реквизит формы типа «Булево», добавьте его в форму. Та же схема работает для ПередЗакрытием: отказ, вопрос, установка флага, повторный Закрыть().
При завершении работы всей программы обработчик ПередЗакрытием получает параметр ЗавершениеРаботы. В этот момент диалоги показывать нельзя — заполните параметр ТекстПредупреждения, и платформа сама покажет пользователю общий список предупреждений.
Частые вопросы
Почему модальность отключили в новых конфигурациях?
Можно ли включить модальность только для одной формы?
Работает ли ОткрытьМодально в расширении конфигурации?
Чем ПоказатьПредупреждение отличается от Сообщить?
ПоказатьПредупреждение() открывает окно, которое пользователь должен закрыть. Сообщить() выводит текст в окно сообщений без блокировки, его легко не заметить.Можно ли задать таймаут для вопроса?
ПоказатьВопрос() есть параметр таймаута в секундах и кнопка по умолчанию. По истечении времени окно закроется, и в оповещение придёт значение КодВозвратаДиалога.Таймаут.