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