Модальность в 1С:Предприятии 8.3: как окна блокируют интерфейс и чем их заменить

· 9 мин

Содержание

Частое заблуждение: модальное окно в 1С «вешает базу» и мешает работать другим пользователям. Это не так. Модальное окно блокирует только интерфейс того сеанса, где его открыли: пока вы не ответите на вопрос или не закроете форму, остальные окна программы у вас не реагируют. Сервер и чужие сеансы продолжают работать.

Для разработчика модальность — это ещё и вопрос архитектуры. В платформе 8.3 у конфигурации есть свойство Режим использования модальности. В типовых конфигурациях на управляемых формах оно стоит в значении «Не использовать», и синхронные вызовы вроде Вопрос() или ОткрытьМодально() там вызывают ошибку. Ниже — как это устроено, чем отличается от обычных окон и как настроить поведение под свою задачу.

Как работает модальное окно в 1С и что именно оно блокирует

Модальное окно — это форма или диалог, который перехватывает ввод пользователя. Пока он открыт, нельзя переключиться на другие окна программы, нажать команду в панели разделов или закрыть основное окно.

В классическом (синхронном) варианте модальность работает и на уровне кода. Встроенный язык останавливается на строке вызова и ждёт, пока пользователь ответит:

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

Здесь выполнение процедуры замирает на Вопрос(). Следующая строка выполнится только после нажатия «Да» или «Нет».

Что блокируется, а что нет:

  • 🔒 Блокируется: ввод во все остальные окна клиентского приложения текущего сеанса.
  • 🔒 Блокируется: выполнение кода процедуры, которая вызвала синхронный диалог.
  • ✅ Не блокируется: сервер 1С, фоновые и регламентные задания.
  • ✅ Не блокируется: работа других пользователей, в том числе с теми же документами.
  • ✅ Не блокируется: обработчики ожидания, подключённые через ПодключитьОбработчикОжидания(), — они продолжают срабатывать в клиентском приложении.

Модальность — свойство клиентской части. Транзакция на сервере не может «висеть» в ожидании ответа пользователя: серверный вызов завершается до того, как клиент покажет окно.

Режимы открытия формы и способы её вызвать

У управляемой формы есть свойство РежимОткрытияОкна. Его задают в конфигураторе в палитре свойств формы или передают параметром в ОткрытьФорму(). Значений три.

ЗначениеЧто блокируетТипичное применение
НезависимыйНичегоСписки, документы, отчёты
БлокироватьОкноВладельцаТолько окно-владелецФорма подбора, ввод реквизитов строки
БлокироватьВесьИнтерфейсВсе окна приложенияОбязательный выбор перед продолжением

Режим БлокироватьОкноВладельца удобен тем, что пользователь видит, к какой форме относится диалог, и может работать с другими окнами. Окно-владелец задают третьим параметром ОткрытьФорму(), обычно это ЭтотОбъект.

Синхронный и асинхронный вызов

Важно различать две вещи: окно, которое блокирует интерфейс, и код, который ждёт ответа. Блокирующее окно можно открыть асинхронно — тогда интерфейс заблокирован, а код идёт дальше.

Синхронные методы (работают только при разрешённой модальности):

  • Вопрос(), Предупреждение();
  • ВвестиЗначение(), ВвестиЧисло(), ВвестиСтроку(), ВвестиДату();
  • ОткрытьФормуМодально() и метод формы ОткрытьМодально().

Асинхронные аналоги:

  • ПоказатьВопрос(), ПоказатьПредупреждение();
  • ПоказатьВводЗначения(), ПоказатьВводЧисла(), ПоказатьВводСтроки(), ПоказатьВводДаты();
  • ОткрытьФорму() с параметром ОписаниеОповещенияОЗакрытии.

Асинхронный вызов получает объект ОписаниеОповещения. В нём указано имя экспортной процедуры, которую платформа вызовет после закрытия окна:

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

&НаКлиенте
Процедура ПослеОтветаНаВопрос(Результат, ДополнительныеПараметры) Экспорт
    Если Результат = КодВозвратаДиалога.Да Тогда
        Записать(Новый Структура("РежимЗаписи", РежимЗаписиДокумента.Проведение));
    КонецЕсли;
КонецПроцедуры

Своя форма возвращает результат так же: внутри неё вызывают Закрыть(Значение), и это значение приходит в первый параметр процедуры-оповещения.

Где модальные окна встречаются в типовых конфигурациях

В «Бухгалтерии предприятия» 3.0, ЗУП 3.1 и «Управлении торговлей» 11 модальность в конфигурации отключена. Но окна, которые блокируют интерфейс, пользователи видят постоянно — они открыты асинхронно.

Типичные случаи:

  • ❓ вопрос при закрытии формы с несохранёнными изменениями: «Данные были изменены. Сохранить изменения?»;
  • 📋 формы подбора номенклатуры в табличную часть документа;
  • 📅 выбор периода отчёта;
  • 🗂️ формы выбора из справочника при нажатии кнопки выбора в поле;
  • ⚙️ формы настройки печати и параметров обработок;
  • 🔐 запрос пароля или подтверждения при подписании документов электронной подписью.

Модальные вызовы в коде остаются в старых внешних обработках, в доработках, написанных под 8.2, и в конфигурациях на обычных формах. Именно они дают ошибку после переноса в базу с отключённой модальностью.

Внешняя обработка с вызовом Вопрос() или Предупреждение() в типовой БП 3.0 упадёт с сообщением Использование модальных окон в данном режиме запрещено!. Код нужно переписать на асинхронные методы — менять свойство типовой конфигурации ради одной обработки не стоит.

Модальное окно, независимая форма и закладки: в чём разница

Путаница возникает из-за того, что «окно» в 1С значит разное в зависимости от интерфейса.

Независимая форма. Открывается в основном окне программы или отдельным окном. Можно держать открытыми десятки таких форм и переключаться между ними.

Закладки и отдельные окна. В интерфейсе «Такси» формы по умолчанию открываются в рабочей области основного окна, а список открытых форм виден на панели открытых. Пользователь может переключить режим на отдельные окна в параметрах программы (Главное меню → Сервис → Параметры). Это аналог старого MDI-подхода: много дочерних окон внутри одного приложения. На модальность настройка не влияет.

Блокирующая форма. Открывается поверх, отдельным плавающим окном. Пока она открыта, окно-владелец или весь интерфейс недоступны.

ПризнакНезависимаяБлокирует владельцаБлокирует весь интерфейс
Можно переключиться на другую формуДаДа, кроме владельцаНет
ОтображениеВ рабочей области или отдельноПлавающее окноПлавающее окно
Ждёт ли код ответаНетТолько при синхронном вызовеТолько при синхронном вызове
Работает в веб-клиентеДаДаДа

Последняя строка часто удивляет. Веб-клиент не умеет синхронно останавливать код, пока пользователь отвечает: браузер не даёт так делать. Поэтому отключение модальности касается именно синхронных методов, а не самих блокирующих окон.

Зависания, «потерянные» диалоги и блокировки данных

Пользователь говорит «1С зависла». Нередко причина — модальное окно, которое оказалось за основным окном или на втором мониторе.

Как это распознать:

  1. Программа не реагирует на клики, но курсор не крутится и загрузка процессора нормальная.
  2. На панели задач Windows у значка 1С есть второе окно.
  3. После Alt+Tab или клика по значку на панели задач появляется диалог с вопросом.

Ответ на вопрос или закрытие диалога сразу возвращает управление.

Модальность и блокировка объекта — разные вещи

Когда пользователь начал редактировать документ, платформа ставит пессимистическую блокировку объекта. Второй пользователь получит сообщение, что объект уже редактируется. Это не модальность: блокировка держится, пока форма объекта открыта и изменена, неважно, открыт ли поверх неё диалог.

Здесь модальность косвенно вредит. Пользователь начал менять документ, получил вопрос, ушёл на обед. Документ заблокирован для коллег всё это время. Решение организационное: закрывать формы, а не бросать их с открытыми диалогами.

Производительность

Сам по себе блокирующий диалог ресурсов не ест. Проблемы дают другие сценарии:

  • 🐢 серверный вызов в цикле с показом вопроса на каждой итерации — каждый раз лишний обмен клиент-сервер;
  • 🐢 тяжёлая форма подбора, которая при открытии читает весь справочник;
  • 🐢 вопрос внутри обработчика ожидания, срабатывающего каждые несколько секунд, — диалоги копятся.

Как настроить режим использования модальности

Свойство конфигурации

Откройте конфигуратор, в дереве конфигурации вызовите свойства корневого элемента и найдите раздел совместимости. Свойство Режим использования модальности принимает три значения:

ЗначениеПоведение синхронных методов
ИспользоватьРаботают как раньше
Использовать с предупреждениямиРаботают, но платформа выдаёт предупреждения о вызове
Не использоватьВызов завершается ошибкой

Свойство появилось в платформе 8.3.3. Для новых конфигураций по умолчанию стоит «Не использовать». Рядом есть похожее свойство Режим использования синхронных вызовов расширений платформы и внешних компонент — оно управляет методами работы с файлами и внешними компонентами, например синхронными диалогами выбора файла.

Не меняйте эти свойства в типовой конфигурации на поддержке: это снимет её с полной поддержки по свойствам и усложнит обновление.

Найти модальные вызовы в своей доработке

В конфигураторе есть два инструмента:

  1. Конфигурация → Проверка конфигурации — в настройках проверки отметьте поиск использования модальности. Список строк с синхронными вызовами появится в окне сообщений.
  2. Меню Конфигурация → Рефакторинг содержит команды поиска и преобразования модальных вызовов. Автоматическое преобразование переписывает простые случаи на ПоказатьВопрос() с процедурой-оповещением.

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

Асинх и Ждать вместо цепочек оповещений

С платформы 8.3.18 есть асинхронные функции. Процедуру помечают словом Асинх, а вызов — оператором Ждать. Код снова читается сверху вниз, но интерфейс не блокируется синхронно:

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

Такой код работает при модальности «Не использовать». Для старых релизов платформы и режима совместимости ниже 8.3.18 остаётся вариант с ОписаниеОповещения.

Вопрос в обработчиках «Перед записью» и «Перед закрытием»

Это главный приём, без которого переход на асинхронность не получается. Обработчик ПередЗаписью формы должен вернуть Отказ сразу, ответа ждать он не может. Схема такая:

  1. При первом вызове ставим Отказ = Истина и показываем ПоказатьВопрос().
  2. В процедуре-оповещении при ответе «Да» поднимаем флаг-реквизит формы, например ЗаписьПодтверждена.
  3. Снова вызываем Записать().
  4. В ПередЗаписью видим флаг, сбрасываем его и пропускаем вопрос.
&НаКлиенте
Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
    Если ЗаписьПодтверждена Тогда
        ЗаписьПодтверждена = Ложь;
        Возврат;
    КонецЕсли;
    Отказ = Истина;
    Оповещение = Новый ОписаниеОповещения("ПослеПодтвержденияЗаписи", ЭтотОбъект, ПараметрыЗаписи);
    ПоказатьВопрос(Оповещение, "Записать изменения?", РежимДиалогаВопрос.ДаНет);
КонецПроцедуры

&НаКлиенте
Процедура ПослеПодтвержденияЗаписи(Результат, ПараметрыЗаписи) Экспорт
    Если Результат = КодВозвратаДиалога.Да Тогда
        ЗаписьПодтверждена = Истина;
        Записать(ПараметрыЗаписи);
    КонецЕсли;
КонецПроцедуры

ЗаписьПодтверждена — реквизит формы типа «Булево», добавьте его в форму. Та же схема работает для ПередЗакрытием: отказ, вопрос, установка флага, повторный Закрыть().

При завершении работы всей программы обработчик ПередЗакрытием получает параметр ЗавершениеРаботы. В этот момент диалоги показывать нельзя — заполните параметр ТекстПредупреждения, и платформа сама покажет пользователю общий список предупреждений.

Какой у вас случай?

Частые вопросы

Почему модальность отключили в новых конфигурациях?
Браузеры не дают сайту синхронно останавливать скрипт до ответа пользователя. Чтобы одна и та же конфигурация работала в тонком, веб- и мобильном клиенте, платформа перешла на асинхронную модель.
Можно ли включить модальность только для одной формы?
Нет. Свойство задаётся для всей конфигурации. На уровне формы можно выбрать лишь режим открытия окна — независимый или блокирующий.
Работает ли ОткрытьМодально в расширении конфигурации?
Расширение подчиняется режиму основной конфигурации. Если в ней модальность отключена, синхронный вызов в расширении тоже даст ошибку.
Чем ПоказатьПредупреждение отличается от Сообщить?
ПоказатьПредупреждение() открывает окно, которое пользователь должен закрыть. Сообщить() выводит текст в окно сообщений без блокировки, его легко не заметить.
Можно ли задать таймаут для вопроса?
Да, у ПоказатьВопрос() есть параметр таймаута в секундах и кнопка по умолчанию. По истечении времени окно закроется, и в оповещение придёт значение КодВозвратаДиалога.Таймаут.