Как открыть форму документа в основном окне из блокирующей интерфейс формы в 1С?

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

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

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

Выясняем причину: почему платформа открывает документ в отдельном окне

Для того чтобы понять логику платформы, проанализируем ситуацию изнутри системы. Когда мы открываем общую форму с параметром РежимОткрытияОкнаФормы.БлокироватьВесьИнтерфейс, происходит следующее:

  1. Платформа полностью блокирует рабочую область основного окна приложения, включая панель открытых разделов и вкладок. Пользователь не может кликнуть ни на один элемент основного окна.
  2. Если из кода этой блокирующей формы мы вызываем метод ОткрытьФорму для нового документа, платформа оказывается перед выбором: куда поместить новое окно?
  3. Попытка открыть форму во вкладках основного окна приведет к тупику (deadlock): поскольку основной интерфейс заблокирован нашей формой оповещения, открывшийся в нем документ также окажется заблокированным и недоступным для редактирования.
  4. Чтобы избежать этой ошибки, платформа принудительно меняет поведение по умолчанию и выносит форму нового документа во вспомогательное независимое окно поверх заблокированного интерфейса.

Именно поэтому стандартные попытки передать в метод ОткрытьФорму различные параметры режима открытия окна не дают желаемого результата, пока вызывающая форма активна и блокирует интерфейс.

Ловушка асинхронного метода Закрыть()

Часто у разработчиков возникает логичная идея: перед открытием формы документа сначала закрыть блокирующую форму оповещения. Код при этом выглядит следующим образом:


&НаКлиенте
Процедура кмСоздатьЗаявку(Команда)
    ЭтаФорма.Закрыть();
    ОткрытьФорму("Документ.Заявки.Форма.ФормаДокумента", ПараметрыЗаявки);
КонецПроцедуры

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

Рассмотрим рабочие архитектурные варианты обхода этой проблемы.

Решение 1. Использование описания оповещения о закрытии (Рекомендуемое)

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

Разберем этот процесс по шагам:

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


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

Шаг 2. В самой форме оповещения при нажатии кнопки создания документа мы не открываем форму документа напрямую. Вместо этого мы закрываем форму оповещения и передаем данные для заполнения документа в качестве параметра закрытия:


&НаКлиенте
Процедура СоздатьДокумент(Команда)
    
    СтруктураДанных = Новый Структура;
    СтруктураДанных.Вставить("УникальныйНомер", НомерЗаявки);
    
    // Закрываем форму и передаем данные в оповещение о закрытии
    Закрыть(СтруктураДанных);
    
КонецПроцедуры

Шаг 3. В процедуре-обработчике оповещения, которая вызывается уже в разблокированном интерфейсе основного окна, мы открываем форму документа:


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

Решение 2. Использование режима блокировки окна владельца

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

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

Для реализации этого метода достаточно при открытии формы оповещения указать соответствующий режим:


ОткрытьФорму(
    "ОбщаяФорма.ФормаОповещения", 
    ПараметрыФормы, 
    ВладелецФормы, 
    , 
    , 
    , 
    , 
    РежимОткрытияОкнаФормы.БлокироватьОкноВладельца
);

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

Важный нюанс: Ключ уникальности формы

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

Чтобы гарантировать, что каждый раз при вызове из оповещения будет открываться новая, чистая вкладка документа, передавайте в качестве ключа уникальности новое уникальное значение:


&НаКлиенте
Процедура ОткрытьНовыйДокументБезБлокировки()
    
    ПараметрыЗаполнения = Новый Структура;
    УникальныйКлюч = Новый УникальныйИдентификатор;
    
    ОткрытьФорму(
        "Документ.Заявки.Форма.ФормаДокумента", 
        ПараметрыЗаполнения, 
        , 
        УникальныйКлюч // Ключ уникальности гарантирует открытие новой вкладки
    );
    
КонецПроцедуры

Использование связки асинхронных вызовов через ОписаниеОповещения и грамотное управление режимами блокировки окон позволит вам создавать плавный, интуитивно понятный и полностью соответствующий стандартам разработки «1С» интерфейс.

← На главную