Как открыть вторую форму внешнего отчета с сохранением данных объекта в 1С 8.3?

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

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

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

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

В чем сложность использования стандартных методов?

Давайте выясним, почему не работают привычные подходы. В обычных формах (на старых версиях платформы) мы могли бы использовать свойство формы ЭтотОбъект или метод ПолучитьФорму() непосредственно у объекта отчета. В управляемом приложении на клиенте у нас нет самого прикладного объекта — вместо него мы оперируем типом ДанныеФормыСтруктура (реквизит Отчет).

Попытка вызвать метод ДанныеФормыВЗначение() на сервере требует обязательного указания типа преобразуемого объекта во втором параметре. Поскольку отчет является внешним, его тип динамически формируется платформой в момент запуска, и мы не можем жестко прописать его в коде конфигурации. К счастью, разработчики 1С предусмотрели альтернативный метод, который избавляет нас от этой проблемы.

Рассмотрим два надежных сценария решения этой задачи.

Способ 1. Получение объекта через РеквизитФормыВЗначение и передача через Временное хранилище

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

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

Шаг 1. Код в модуле основной формы отчета

Для начала нам нужно написать процедуру вызова второй формы. На клиенте мы инициируем процесс, затем на сервере преобразуем реквизит формы в прикладной объект с помощью функции РеквизитФормыВЗначение(). Прелесть этой функции в том, что для нее не требуется указывать тип объекта — платформа определит его автоматически.

Посмотрим на пример реализации кода в основной форме:


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

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

Шаг 2. Код в модуле второй (открываемой) формы

Теперь перейдем в модуль второй формы (в нашем примере это форма НастройкаПорядкаОпераций). Нам необходимо перехватить переданный адрес хранилища в обработчике создания формы на сервере, извлечь из него объект и заполнить им данные текущей формы.

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


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

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

Способ 2. Использование метода КопироватьДанныеФормы на клиенте

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

Для этого в платформе «1С:Предприятие 8.3» существует быстрый и эффективный метод КопироватьДанныеФормы(). Рассмотрим пример его использования.

Код в основной форме отчета для быстрого копирования:


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

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

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

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

Для реализации обратной связи нам понадобится использовать механизм описания оповещения о закрытии. Давайте разберем по шагам, как настроить этот возврат.

1. Модифицируем код вызова в основной форме:

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


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

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

2. Код во второй (закрываемой) форме:

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


&НаКлиенте
Процедура КомандаОК(Команда)
    
    // Закрываем форму и передаем текущую структуру данных "Отчет" в качестве результата
    Закрыть(Отчет);
    
КонецПроцедуры

Подведем итоги

Мы подробно проанализировали проблему работы с контекстом внешнего отчета в управляемых формах 1С 8.3. Использование функции РеквизитФормыВЗначение() позволяет легко обходить ограничения платформы, связанные с отсутствием фиксированного типа у внешних объектов на этапе разработки.

В зависимости от ваших задач вы можете выбрать:

  1. Способ с временным хранилищем — если вам критически важна работа бизнес-логики в модуле объекта отчета из новой формы.
  2. Способ с КопироватьДанныеФормы — если вам нужно просто и быстро синхронизировать визуальные реквизиты и настройки на клиенте.

Оба этих метода являются стандартными, безопасными и рекомендованными к использованию при разработке на платформе «1С:Предприятие 8.3».

← На главную