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

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

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

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

Проблема использования стандартного метода ОткрытьФорму

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

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

Решение 1. Эмуляция «Описания оповещения» через экспортную переменную

Поскольку метод ПолучитьФорму() для обычных форм не поддерживает аргумент «ОповещениеОЗакрытии», мы можем передать объект ОписаниеОповещения напрямую в саму открываемую форму как параметр. Для этого мы объявим экспортную переменную в модуле обычной формы.

Разберем этот изящный способ по шагам.

Шаг 1. Настройка вызываемой (обычной) формы

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


Перем мОписаниеОповещения Экспорт;

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

Шаг 2. Вызов обычной формы из управляемой (или другой обычной) формы

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


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

&НаКлиенте
Процедура ОбработатьЗакрытиеОбычнойФормы(Результат, ДополнительныеПараметры) Экспорт
    
    Если Результат <> Неопределено Тогда
        ПоказатьПредупреждение(, "Получен результат: " + Результат.ЗначениеВыбора);
    КонецЕсли;
    
КонецПроцедуры

Этот способ является наиболее гибким, так как позволяет использовать всю мощь асинхронного программирования 1С без привязки к иерархии окон.

Решение 2. Передача параметров через экспортные переменные и инициализация

В обычных формах нет события ПриСозданииНаСервере, а значения переменных, переданных после ПолучитьФорму(), становятся доступны в событии ПриОткрытии на клиенте. Чтобы правильно инициализировать данные, мы можем использовать следующую схему:

  1. Объявить экспортные переменные в модуле обычной формы.
  2. Присвоить им значения сразу после получения формы.
  3. Если требуется сложная логика обработки параметров до открытия (аналог серверного создания), вызвать специально созданный экспортный метод инициализации.

Проанализируем пример кода для вызываемой формы:


Перем ПараметрИмя Экспорт;
Перем ПараметрПриветствие Экспорт;

Процедура ИнициализироватьФорму() Экспорт
    // Данный метод вызывается ДО открытия формы для предварительной подготовки данных
    Если ПараметрИмя = "Олег" Тогда
        ПараметрПриветствие = "Здравствуйте, Олег!";
    КонецЕсли;
КонецПроцедуры

Процедура ПриОткрытии()
    // Здесь параметры уже гарантированно заполнены
    ЭлементыФормы.НадписьПриветствие.Значение = ПараметрПриветствие;
КонецПроцедуры

Код вызова формы будет выглядеть следующим образом:


Ф = ПолучитьФорму("ОбщаяФорма.НашаОбычнаяФорма");
Ф.ПараметрИмя = "Олег";
Ф.ИнициализироватьФорму(); // Явный вызов логики подготовки данных
Ф.Открыть();

Решение 3. Обращение к владельцу формы напрямую

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

Посмотрим, как реализовать обратную передачу через экспортный метод владельца:


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

В вызывающей форме достаточно передать себя (ЭтотОбъект) в качестве владельца при вызове:


// В вызывающей форме
ФормаВыбора = ПолучитьФорму("ОбщаяФорма.НашаОбычнаяФорма", ЭтотОбъект);
ФормаВыбора.Открыть();

Решение 4. Использование механизма выбора и свойства ЗакрыватьПриВыборе

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

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

  1. В обычной форме установим свойство ЗакрыватьПриВыборе в значение Истина (это можно сделать как в конфигураторе, так и программно).
  2. В коде обычной формы при совершении выбора вызовем метод ОповеститьОВыборе(ВыбранноеЗначение).
  3. В форме-владельце обработаем стандартное событие ОбработкаВыбора.

Посмотрим на пример кода в обычной форме:


Процедура СписокВыбор(Элемент, ВыбраннаяСтрока, Колонка, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь;
    // Оповещаем владельца о выборе. Форма закроется автоматически.
    ОповеститьОВыборе(ВыбраннаяСтрока);
КонецПроцедуры

Решение 5. Безопасное глобальное оповещение с уникальным ключом

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

Чтобы избежать хаоса, мы можем использовать технику уникального ключа (UID). При открытии подчиненной формы мы передаем ей уникальный идентификатор вызывающей формы. При отправке оповещения этот идентификатор возвращается обратно, и вызывающая форма реагирует только на «свои» сообщения.

Реализуем этот механизм:

Код в вызывающей форме:


&НаКлиенте
Процедура ОткрытьФормуСИдентификатором()
    
    ИдентификаторОкна = Новый УникальныйИдентификатор;
    
    Ф = ПолучитьФорму("ОбщаяФорма.НашаОбычнаяФорма");
    Ф.ИдентификаторВызывающейФормы = ИдентификаторОкна;
    Ф.Открыть();
    
КонецПроцедуры

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

Код в открываемой обычной форме:


Перем ИдентификаторВызывающейФормы Экспорт;

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

Резюме

Мы подробно проанализировали различные варианты обхода модальности при работе с обычными формами в 1С. Каждый из способов хорош в своей ситуации:

← На главную