При переходе на новые стандарты разработки в среде 1С:Предприятие программисты часто сталкиваются с необходимостью поддержки старого кода. Одной из типичных проблем является работа с обычными формами в режиме управляемого приложения или толстого клиента. Разработчики привыкли к удобному методу ОткрытьФорму(), который позволяет в один вызов передать параметры, назначить владельца и определить процедуру-обработчик закрытия через ОписаниеОповещения. Однако при работе с обычными формами этот подход напрямую не работает.
В этой статье мы подробно разберем, как передать параметры в обычную форму, а также как элегантно вернуть результат работы в вызывающую форму, полностью отказавшись от использования устаревшего и нерекомендуемого модального режима (метода ОткрытьМодально()).
Метод ОткрытьФорму() ориентирован в первую очередь на работу с управляемыми формами. Если попытаться передать в него имя обычной формы, платформа может создать автоматическую «обертку», но доступ к ее специфическим свойствам и передача параметров через этот метод будут крайне ограничены. Кроме того, у обычных форм отсутствует стандартное расширение Параметры и событие ПриСозданииНаСервере, где эти параметры можно было бы перехватить.
Поэтому для работы с обычными формами мы продолжаем использовать классический метод ПолучитьФорму(), но модифицируем подход к передаче параметров и возврату данных.
Поскольку метод ПолучитьФорму() для обычных форм не поддерживает аргумент «ОповещениеОЗакрытии», мы можем передать объект ОписаниеОповещения напрямую в саму открываемую форму как параметр. Для этого мы объявим экспортную переменную в модуле обычной формы.
Разберем этот изящный способ по шагам.
Шаг 1. Настройка вызываемой (обычной) формы
В самом верху модуля обычной формы объявим экспортную переменную, которая будет хранить наше оповещение, а также обработаем событие закрытия:
Перем мОписаниеОповещения Экспорт;
Процедура ПриЗакрытии()
// Проверяем, было ли передано описание оповещения
Если мОписаниеОповещения <> Неопределено Тогда
СтруктураРезультата = Новый Структура;
СтруктураРезультата.Вставить("ЗначениеВыбора", "Олег");
СтруктураРезультата.Вставить("Статус", "Успешно");
// Выполняем вызов процедуры-обработчика в вызывающей форме
ВыполнитьОбработкуОповещения(мОписаниеОповещения, СтруктураРезультата);
КонецЕсли;
КонецПроцедуры
Шаг 2. Вызов обычной формы из управляемой (или другой обычной) формы
В вызывающей форме мы подготавливаем описание оповещения, получаем форму, передаем в нее это описание как в обычное экспортное свойство и открываем:
&НаКлиенте
Процедура ОткрытьОбычнуюФорму()
// Создаем описание оповещения, указывая имя принимающей процедуры
ОповещениеОЗакрытии = Новый ОписаниеОповещения("ОбработатьЗакрытиеОбычнойФормы", ЭтотОбъект);
// Получаем обычную форму стандартным путем
ОбычнаяФорма = ПолучитьФорму("ОбщаяФорма.НашаОбычнаяФорма");
// Напрямую передаем описание оповещения в экспортную переменную модуля обычной формы
ОбычнаяФорма.мОписаниеОповещения = ОповещениеОЗакрытии;
// Открываем форму в немодальном режиме
ОбычнаяФорма.Открыть();
КонецПроцедуры
&НаКлиенте
Процедура ОбработатьЗакрытиеОбычнойФормы(Результат, ДополнительныеПараметры) Экспорт
Если Результат <> Неопределено Тогда
ПоказатьПредупреждение(, "Получен результат: " + Результат.ЗначениеВыбора);
КонецЕсли;
КонецПроцедуры
Этот способ является наиболее гибким, так как позволяет использовать всю мощь асинхронного программирования 1С без привязки к иерархии окон.
В обычных формах нет события ПриСозданииНаСервере, а значения переменных, переданных после ПолучитьФорму(), становятся доступны в событии ПриОткрытии на клиенте. Чтобы правильно инициализировать данные, мы можем использовать следующую схему:
Проанализируем пример кода для вызываемой формы:
Перем ПараметрИмя Экспорт;
Перем ПараметрПриветствие Экспорт;
Процедура ИнициализироватьФорму() Экспорт
// Данный метод вызывается ДО открытия формы для предварительной подготовки данных
Если ПараметрИмя = "Олег" Тогда
ПараметрПриветствие = "Здравствуйте, Олег!";
КонецЕсли;
КонецПроцедуры
Процедура ПриОткрытии()
// Здесь параметры уже гарантированно заполнены
ЭлементыФормы.НадписьПриветствие.Значение = ПараметрПриветствие;
КонецПроцедуры
Код вызова формы будет выглядеть следующим образом:
Ф = ПолучитьФорму("ОбщаяФорма.НашаОбычнаяФорма");
Ф.ПараметрИмя = "Олег";
Ф.ИнициализироватьФорму(); // Явный вызов логики подготовки данных
Ф.Открыть();
Если вызывающая форма открывает подчиненную (обычную) форму, мы можем явно указать владельца при получении формы. Это дает подчиненной форме прямой доступ к контексту родительского окна через свойство ВладелецФормы.
Посмотрим, как реализовать обратную передачу через экспортный метод владельца:
// В модуле обычной формы (при закрытии или нажатии кнопки ОК)
Процедура КнопкаОКНажатие(Кнопка)
// Проверяем, что у формы задан владелец и у него есть нужный нам метод
Попытка
ВладелецФормы.ОбработатьВыборИзОбычнойФормы("Передаваемые данные");
Закрыть();
Исключение
// Обработка ситуации, если форма открыта без владельца или метод отсутствует
Закрыть();
КонецПопытки;
КонецПроцедуры
В вызывающей форме достаточно передать себя (ЭтотОбъект) в качестве владельца при вызове:
// В вызывающей форме
ФормаВыбора = ПолучитьФорму("ОбщаяФорма.НашаОбычнаяФорма", ЭтотОбъект);
ФормаВыбора.Открыть();
Если обычная форма используется исключительно для выбора значения (например, подбор элемента или выбор режима работы), можно задействовать стандартную платформенную схему выбора. При этом вызывающая форма может быть как управляемой, так и обычной.
Для реализации этого сценария выполним следующие настройки:
ЗакрыватьПриВыборе в значение Истина (это можно сделать как в конфигураторе, так и программно).ОповеститьОВыборе(ВыбранноеЗначение).ОбработкаВыбора.Посмотрим на пример кода в обычной форме:
Процедура СписокВыбор(Элемент, ВыбраннаяСтрока, Колонка, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// Оповещаем владельца о выборе. Форма закроется автоматически.
ОповеститьОВыборе(ВыбраннаяСтрока);
КонецПроцедуры
Использование глобального метода Оповестить() — очень простой способ передать данные обратно. Однако у него есть существенный недостаток: оповещение рассылается абсолютно всем открытым формам, что может вызвать нежелательные срабатывания в чужих окнах.
Чтобы избежать хаоса, мы можем использовать технику уникального ключа (UID). При открытии подчиненной формы мы передаем ей уникальный идентификатор вызывающей формы. При отправке оповещения этот идентификатор возвращается обратно, и вызывающая форма реагирует только на «свои» сообщения.
Реализуем этот механизм:
Код в вызывающей форме:
&НаКлиенте
Процедура ОткрытьФормуСИдентификатором()
ИдентификаторОкна = Новый УникальныйИдентификатор;
Ф = ПолучитьФорму("ОбщаяФорма.НашаОбычнаяФорма");
Ф.ИдентификаторВызывающейФормы = ИдентификаторОкна;
Ф.Открыть();
КонецПроцедуры
&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
// Проверяем имя события и соответствие уникального ключа
Если ИмяСобытия = "ЗавершениеВыбораВОбычнойФорме"
И Параметр.ИдентификаторОкна = ИдентификаторОкна Тогда
Результат = Параметр.Значение;
// Обрабатываем полученный результат
КонецЕсли;
КонецПроцедуры
Код в открываемой обычной форме:
Перем ИдентификаторВызывающейФормы Экспорт;
Процедура ПриЗакрытии()
Если ЗначениеЗаполнено(ИдентификаторВызывающейФормы) Тогда
ПараметрыСообщения = Новый Структура;
ПараметрыСообщения.Вставить("ИдентификаторОкна", ИдентификаторВызывающейФормы);
ПараметрыСообщения.Вставить("Значение", "Передаваемый результат");
Оповестить("ЗавершениеВыбораВОбычнойФорме", ПараметрыСообщения);
КонецЕсли;
КонецПроцедуры
Мы подробно проанализировали различные варианты обхода модальности при работе с обычными формами в 1С. Каждый из способов хорош в своей ситуации: