При разработке внешних печатных форм в среде 1С:Предприятие 8.3 программисты часто сталкиваются с архитектурным барьером управляемого приложения. Суть проблемы заключается в том, что внешняя печатная форма, вызываемая через стандартные механизмы Библиотеки стандартных подсистем (БСП), выполняется в контексте сервера и «не видит» экземпляр формы, из которой она была запущена. Особенно остро этот вопрос встает, когда на форме находится дерево значений с программно созданными или специфическими колонками, которые необходимо обработать для вывода на печать. Рассмотрим подробно, как решить эту задачу, сохранив чистоту кода и не прибегая к правкам типовой конфигурации.
Прежде всего проанализируем, почему стандартное обращение к метаданным не дает результата. Когда мы обращаемся к Метаданные.ОбщиеФормы.НужнаяФорма, мы получаем описание объекта, заложенного в конфигураторе. Однако Реквизиты формы (в том числе дерево значений) не являются частью метаданных объекта в классическом понимании. Они создаются в момент инициализации экземпляра формы в памяти. Если дерево значений или его колонки создавались программно на клиенте или сервере формы, информация о них доступна только внутри этого конкретного объекта УправляемаяФорма.
Поскольку модуль объекта внешней печатной формы (процедура Печать) работает на сервере без прямой ссылки на форму-владельца, мы не можем просто «дотянуться» до колонок. Выясним, какие инструменты платформы и БСП позволяют нам пробросить эти данные.
Это наиболее правильный и рекомендуемый путь при работе с БСП. Вместо того чтобы сразу пытаться выполнить печать на сервере, мы сначала перехватываем управление на стороне клиента, где форма и ее дерево значений нам полностью доступны. Рассмотрим этот алгоритм по шагам.
Во-первых, в модуле объекта внешней печатной формы в функции СведенияОВнешнейОбработке() необходимо указать правильный тип команды. Вместо привычного ВызовСерверногоМетода мы используем ВызовКлиентскогоМетода.
ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке("2.2.2.1");
НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
НоваяКоманда.Представление = НСтр("ru = 'Печать дерева значений'");
НоваяКоманда.Идентификатор = "ПечатьДерева";
НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовКлиентскогоМетода();
Во-вторых, в модуле формы внешней обработки (не в модуле объекта!) создаем экспортную процедуру Печать. В этой процедуре мы имеем доступ к владельцу формы, а значит, и к самому дереву значений.
&НаКлиенте
Процедура ВыполнитьКоманду(ИдентификаторКоманды, ОбъектыПечати) Экспорт
// Получаем доступ к дереву на форме-владельце
// Предположим, дерево называется "ДеревоДанных"
ДеревоНаФорме = ВладелецФормы.Объект.ДеревоДанных;
// Подготовим параметры для передачи на сервер
ДополнительныеПараметры = Новый Структура;
ДополнительныеПараметры.Вставить("ДанныеДерева", ДеревоНаФорме);
// Вызываем стандартный механизм печати БСП, передавая накопленные данные
УправлениеПечатьюКлиент.ВыполнитьКомандуПечати("ВнешняяОбработка.ИмяВашейОбработки",
ИдентификаторКоманды, ОбъектыПечати, ВладелецФормы, ДополнительныеПараметры);
КонецПроцедуры
Если мы передали дерево в составе структуры параметров (как показано выше), на сервере в процедуре Печать оно придет как объект типа ДанныеФормыДерево. Напрямую работать с его колонками как с коллекцией метаданных неудобно. Проанализируем ситуацию: чтобы получить полноценный объект ДеревоЗначений со всеми колонками и типами, используем функцию ДанныеФормыВЗначение.
Рассмотрим пример кода в модуле объекта внешней печатной формы:
Процедура Печать(МассивОбъектов, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
// Извлекаем дерево из дополнительных параметров, если они были переданы
Если ПараметрыВывода.Свойство("ДополнительныеПараметры") Тогда
ДанныеДереваУФ = ПараметрыВывода.ДополнительныеПараметры.ДанныеДерева;
// Преобразуем ДанныеФормы в реальное ДеревоЗначений
ДеревоОбъект = ДанныеФормыВЗначение(ДанныеДереваУФ, Тип("ДеревоЗначений"));
// Теперь нам доступны колонки
Для Каждого Колонка Из ДеревоОбъект.Колонки Цикл
ИмяКолонки = Колонка.Имя;
ТипКолонки = Колонка.ТипЗначения;
// Выполняем заполнение печатной формы
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Важный момент: Передача всего дерева значений целиком в параметрах может быть накладной для памяти, если дерево содержит тысячи строк. В этом случае рассмотрим альтернативный вариант с использованием временного хранилища.
Если дерево значений очень объемное, правильнее будет выгрузить его в обычное ДеревоЗначений на стороне формы, поместить во временное хранилище и передать на сервер только адрес (строку GUID).
Разберем этот процесс по шагам:
РеквизитФормыВЗначение("ДеревоНаФорме").ПоместитьВоВременноеХранилище(ДеревоОбъект, УникальныйИдентификатор).ДополнительныеПараметры.ПолучитьИзВременногоХранилища(Адрес).Если конфигурация позволяет использовать расширения, мы можем применить более элегантный подход. Выясним причину: часто дерево значений на общей форме заполняется какими-то специфическими данными, которые не сохраняются в БД. Создав расширение для этой общей формы, мы можем добавить процедуру &После для метода, который формирует дерево, и сохранить структуру колонок в какой-либо глобальный параметр сеанса или передать его через временное хранилище, доступное для печатной формы.
Тем не менее, для внешних печатных форм связка ТипКомандыВызовКлиентскогоМетода + ДанныеФормыВЗначение остается «золотым стандартом», так как она не требует изменения метаданных конфигурации и работает в рамках типовой логики БСП.
Проанализировав проблему получения колонок дерева значений, мы пришли к выводу, что ключевым инструментом является правильное управление контекстом. Не пытайтесь найти форму на сервере — её там нет в том виде, в котором она представлена пользователю. Вместо этого:
ВладелецФормы на клиенте для доступа к данным.ДанныеФормыКоллекция (или дерево) в типизированные объекты 1С через ДанныеФормыВЗначение.ДополнительныеПараметры в механизмах печати БСП для транспортировки данных между клиентом и сервером.Такой подход гарантирует, что ваша внешняя печатная форма будет работать стабильно даже при обновлении конфигурации, так как она полагается на документированные методы платформы и типовых подсистем.