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