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