При переходе от обычного приложения к управляемому многие разработчики сталкиваются с трудностями понимания клиент-серверной архитектуры 1С. Попытка использовать привычные старые подходы — такие как глобальные переменные, объявленные с ключевым словом Экспорт в модуле формы, для передачи данных с сервера на клиент — неизбежно приводит к ошибкам. Одна из самых частых: "Значение не является значением объектного типа" при обращении к реквизитам или переменным формы.
В этой статье мы подробно разберем, почему возникает эта ошибка, проанализируем архитектурные ограничения платформы 1С 8.3 и рассмотрим четыре надежных и современных способа передачи данных между модулями.
Рассмотрим исходную ситуацию. Разработчик пытается передать инвентарный номер основного средства из модуля менеджера (серверный контекст) в общую форму печати документов (клиентский контекст), используя конструкцию:
// В модуле ОбщаяФорма.ПечатьДокументов
&НаКлиенте
Перем МояПеременная Экспорт;
И затем пытается записать туда значение из модуля менеджера:
// В модуле менеджера ОсновногоСредства
Ф = ПолучитьФорму("ОбщаяФорма.ПечатьДокументов");
Ф.МояПеременная = ПП; // Ошибка: Значение не является значением объектного типа (МояПеременная)
Давайте разберем по шагам, почему этот код принципиально неработоспособен в управляемом приложении:
&НаКлиенте) физически существует только в оперативной памяти клиентского компьютера (в тонком или веб-клиенте). Сервер ничего не знает о существовании клиентской переменной конкретного открытого окна.ПолучитьФорму. В управляемом приложении вызов ПолучитьФорму на сервере возвращает лишь серверный "объект-пустышку" (прокси), у которого нет доступа к клиентским переменным модуля. Попытка напрямую присвоить значение свойству Ф.МояПеременная вызывает закономерный отказ платформы, так как серверная проекция формы не содержит этого свойства.Как же решить эту задачу правильно? Рассмотрим эффективные и стандартные способы передачи строки (в нашем примере — инвентарного номера) для формирования имени файла PDF.
---
Если вам необходимо открыть форму и передать в нее информацию, стандартный и самый чистый способ — использовать параметры формы. Вместо использования глобальных переменных в модуле формы мы создаем специальный реквизит, который будет хранить состояние.
Разберем этот процесс по шагам.
Шаг 1. Создание реквизита в форме-приемнике
Откройте форму ОбщаяФорма.ПечатьДокументов в конфигураторе. На вкладке "Реквизиты" создайте новый реквизит формы, например, ИнвентарныйНомер с типом Строка.
Шаг 2. Передача параметра при открытии формы на Клиенте
В форме-источнике (откуда вы хотите вызвать печать) мы подготавливаем структуру параметров и открываем форму:
&НаКлиенте
Процедура ОткрытьПечатьДокументов()
// Формируем структуру параметров для передачи в форму
ПараметрыОткрытия = Новый Структура;
ПараметрыОткрытия.Вставить("ИнвентарныйНомер", "ОС-0000342");
// Открываем форму, передавая структуру параметров
ОткрытьФорму("ОбщаяФорма.ПечатьДокументов", ПараметрыОткрытия);
КонецПроцедуры
Шаг 3. Прием параметра в форме-приемнике на Сервере
При открытии формы срабатывает обработчик события ПриСозданииНаСервере. Именно здесь мы перехватываем переданное значение и записываем его в реквизит формы:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Проверяем, передан ли наш параметр
Если Параметры.Свойство("ИнвентарныйНомер") Тогда
// Заполняем реквизит формы, который теперь будет доступен везде
Объект.ИнвентарныйНомер = Параметры.ИнвентарныйНомер;
КонецЕсли;
КонецПроцедуры
Шаг 4. Использование значения на Клиенте
Теперь в любом клиентском методе формы ОбщаяФорма.ПечатьДокументов (включая процедуру сохранения в PDF) вы можете напрямую обращаться к этому реквизиту:
&НаКлиенте
Процедура СохранитьПечатныеФормыВПапку()
// Читаем значение из реквизита формы
ИмяФайла = "Карточка_" + СокрЛП(Объект.ИнвентарныйНомер) + ".pdf";
ПолныйПуть = Папка + ИмяФайла;
ДвоичныеДанные.Записать(ПолныйПуть);
КонецПроцедуры
---
Если ваша конфигурация разработана на базе Библиотеки Стандартных Подсистем (БСП), то вам вообще не нужно вручную открывать общие формы и изобретать велосипед с передачей параметров. В БСП подсистема печати уже содержит встроенный функционал автоматического формирования имени файла для сохранения.
Проанализируем, как использовать свойство ИмяФайлаПечатнойФормы в процедуре печати модуля менеджера:
// В модуле менеджера вашего справочника или документа
Процедура Печать(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
// Проверяем, нужно ли формировать наш макет
Если УправлениеПечатью.НужноПечататьМакет(КоллекцияПечатныхФорм, "ИнвентарнаяКарточка") Тогда
// Формируем табличный документ стандартным методом
ТабДок = СформироватьИнвентарнуюКарточку(МассивОбъектов);
// Регистрируем документ в коллекции
УправлениеПечатью.ВывестиТабличныйДокументВКоллекцию(
КоллекцияПечатныхФорм,
"ИнвентарнаяКарточка",
"Инвентарная карточка ОС",
ТабДок
);
// Настраиваем имя файла по умолчанию для сохранения
ПечатнаяФорма = УправлениеПечатью.СведенияОПечатнойФорме(КоллекцияПечатныхФорм, "ИнвентарнаяКарточка");
Если ПечатнаяФорма <> Неопределено Тогда
// Задаем соответствие имен файлов для каждого объекта
ИменаФайлов = Новый Соответствие;
Для Каждого Ссылка Из МассивОбъектов Цикл
// Получаем инвентарный номер через БСП-функцию чтения реквизитов
ИнвНомер = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "ИнвентарныйНомер");
ИменаФайлов.Вставить(Ссылка, "Карточка_ОС_" + СокрЛП(ИнвНомер));
КонецЦикла;
// Передаем соответствие в БСП
ПечатнаяФорма.ИмяФайлаПечатнойФормы = ИменаФайлов;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
При таком подходе БСП самостоятельно передаст имя файла в общую форму печати документов. Когда пользователь решит сохранить печатную форму на диск или отправить по почте, система автоматически предложит корректное имя файла без написания сложного кода на клиенте.
---
Если печатная форма всегда выводится в единственном экземпляре, есть еще более простой "лайфхак" в рамках БСП. Имя файла при сохранении по умолчанию формируется на основе синонима макета. Мы можем динамически изменить его прямо на сервере в модуле менеджера:
// В процедуре Печать модуля менеджера:
ТабДок = СформироватьИнвентарнуюКарточку(МассивОбъектов);
// Добавляем табличный документ в коллекцию
УправлениеПечатью.ВывестиТабличныйДокументВКоллекцию(
КоллекцияПечатныхФорм,
"ИнвентарнаяКарточка",
"Инвентарная карточка ОС",
ТабДок
);
// Динамически переопределяем СинонимМакет для БСП
Для Каждого СтрокаКоллекции Из КоллекцияПечатныхФорм Цикл
Если СтрокаКоллекции.ИмяМакета = "ИнвентарнаяКарточка" Тогда
// Получаем инвентарный номер из объекта
ИнвНомер = СокрЛП(МассивОбъектов[0].ИнвентарныйНомер);
СтрокаКоллекции.СинонимМакета = "Карточка_ОС_№" + ИнвНомер;
КонецЕсли;
КонецЦикла;
Когда откроется стандартная форма печати БСП, заголовок вкладки и дефолтное имя сохраняемого PDF-файла примут вид Карточка_ОС_№[Номер].pdf.
---
Зачастую перед разработчиком стоит задача не просто показать форму пользователю, а автоматически сохранить файл в фоновом режиме (например, при проведении документа или по расписанию). В этом случае открывать клиентские формы вообще не нужно. Вся логика реализуется на сервере:
&НаСервере
Процедура СохранитьПечатнуюФормуНаДискНаСервере(СсылкаНаОбъект, ПутьКПапке)
// 1. Получаем макет напрямую из менеджера объекта
ТабДок = Справочники.ОсновныеСредства.ПолучитьМакетПечатнойФормы(СсылкаНаОбъект);
// 2. Формируем уникальное имя файла на основе реквизитов
ИнвентарныйНомер = СокрЛП(СсылкаНаОбъект.ИнвентарныйНомер);
ИмяФайла = "Карточка_" + ИнвентарныйНомер + ".pdf";
ПолныйПуть = ПутьКПапке + "\" + ИмяФайла;
// 3. Записываем файл в формате PDF штатными средствами платформы
ТабДок.Записать(ПолныйПуть, ТипФайлаТабличногоДокумента.PDF);
КонецПроцедуры
Этот метод работает молниеносно, не требует взаимодействия с клиентом, не расходует оперативную память на отрисовку окон и идеально подходит для автоматизации бизнес-процессов.
---
Для создания надежных и производительных решений в управляемом приложении 1С 8.3 рекомендуем придерживаться следующих правил:
ИмяФайлаПечатнойФормы и СинонимМакета) — это сэкономит вам десятки строк кода и убережет от ошибок при обновлениях конфигурации.