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