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

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

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

Анализируем причину возникновения проблемы

Разберем ситуацию, с которой сталкиваются многие разработчики. В процедуре ПриНачалеРаботыСистемы мы пытаемся открыть две дополнительные формы, привязывая их к основному окну рабочего стола. На первый взгляд код выглядит логично:


Процедура ПриНачалеРаботыСистемы()
    ОкноРабочегоСтола = Неопределено;
    Окна = ПолучитьОкна();
    Для Каждого Окно Из Окна Цикл
        Если Окно.Основное Тогда
            ОкноРабочегоСтола = Окно;
        КонецЕсли;
    КонецЦикла;
    
    Если ОкноРабочегоСтола <> Неопределено Тогда
        // Открываем первую форму
        ОткрытьФорму("ОбщаяФорма.ДополнительныйРабочийСтол_1",,,, ОкноРабочегоСтола,,, РежимОткрытияОкнаФормы.Независимый);
        // Открываем вторую форму
        ОткрытьФорму("ОбщаяФорма.ДополнительныйРабочийСтол_2",,,, ОкноРабочегоСтола,,, РежимОткрытияОкнаФормы.Независимый);
    КонецЕсли;
КонецПроцедуры

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

Решение №1: Изменение порядка инициализации

Проанализируем самый простой, «быстрый», но не всегда универсальный способ. Если мы точно знаем, что одна из форм вызывает диалоговые окна, а другая — нет, мы можем просто поменять их местами в коде. Рассмотрим, как это выглядит на практике:

  1. Выясняем, какая из форм инициирует вызов ПоказатьПредупреждение или ПоказатьВопрос.
  2. Переносим вызов открытия этой формы в самый конец очереди.

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

Решение №2: Использование разового обработчика ожидания

Это более надежный и профессиональный метод, который позволяет «разнести» процессы открытия форм во времени и дать интерфейсу системы стабилизироваться. Рассмотрим по шагам, как реализовать этот механизм:

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


// В модуле управляемого приложения
Процедура ПриНачалеРаботыСистемы()
    // Открываем первую форму сразу
    ОткрытьФорму("ОбщаяФорма.ДополнительныйРабочийСтол_1");
    
    // Подключаем обработчик ожидания для открытия второй формы через 0.1 секунды
    ПодключитьОбработчикОжидания("Подключаемый_ОткрытьВторуюФорму", 0.1, Истина);
КонецПроцедуры

Процедура Подключаемый_ОткрытьВторуюФорму() Экспорт
    ОткрытьФорму("ОбщаяФорма.ДополнительныйРабочийСтол_2");
КонецПроцедуры

Использование параметра Истина в методе ПодключитьОбработчикОжидания делает вызов однократным. Этого времени (0.1 — 0.5 сек) достаточно, чтобы платформа 1С отрисовала первое окно и перешла в режим ожидания действий пользователя, что исключает конфликт владения окнами.

Решение №3: Перенос логики предупреждения в обработчик ожидания самой формы

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

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


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    // Вместо ПоказатьПредупреждение("Текст");
    ПодключитьОбработчикОжидания("ПоказатьВажноеСообщение", 0.1, Истина);
КонецПроцедуры

&НаКлиенте
Процедура ПоказатьВажноеСообщение()
    ПоказатьПредупреждение(, "Внимание! Проверьте данные на рабочем столе.");
КонецПроцедуры

Этот подход решает проблему в корне: вторая форма, открываемая в ПриНачалеРаботыСистемы, успеет создаться нормально, так как первая форма еще не успела инициировать окно предупреждения в момент своего фактического открытия.

Решение №4: Использование неблокирующих оповещений

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

В современных версиях 1С (8.3.x) рекомендуется использовать метод ПоказатьОповещениеПользователя. Разберем его преимущества в данном контексте:


// Пример использования в первой форме
ТекстСообщения = "У вас есть 5 необработанных заявок!";
ПоказатьОповещениеПользователя("Внимание", "Перейти к списку", ТекстСообщения, БиблиотекаКартинок.Важное);

Рекомендации по проектированию интерфейса при запуске

Подводя итог, приведем несколько важных правил, которые помогут избежать проблем с окнами в 1С:

  1. Явное указание владельца: При использовании ОткрытьФорму старайтесь всегда явно определять, к чему должна быть привязана форма. Если форма должна быть частью рабочего стола, убедитесь, что в параметрах не передается временный контекст.
  2. Избегайте модальности: Старайтесь минимизировать использование любых методов, прерывающих поток исполнения кода (даже асинхронных диалогов) в процедурах инициализации интерфейса.
  3. Событийная модель: Если одна форма зависит от другой, используйте механизм Оповестить() и ОбработкаОповещения вместо жесткой привязки в одном цикле открытия.
  4. Проверка прав и условий на сервере: Все проверки, которые могут привести к показу предупреждения (например, «У вас нет прав» или «Заполните данные»), лучше проводить заранее в ПриСозданииНаСервере, передавая результат на клиента через параметры формы, чтобы клиентская часть лишь отрабатывала финализацию интерфейса.

Выбор конкретного метода зависит от требований вашего проекта, но использование обработчика ожидания (Решение №2 или №3) является наиболее универсальным и стабильным «best practice» для платформы 1С:Предприятие 8.3.

← На главную