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