К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как получить макет на клиенте в 1С: рабочие способы и ограничения

Как получить макет на клиенте в 1С: почему ПолучитьМакет недоступен в клиентском контексте, серверные вызовы, работа с табличным документом и типовые ошибки.

Разработчики на платформе 1С:Предприятие регулярно сталкиваются с ситуацией: в клиентской процедуре формы нужно получить макет (табличный документ, текст, двоичные данные), а вызов ПолучитьМакет() приводит к ошибке компиляции или выполнения. Причина проста — метод получения макета доступен только на сервере, и это архитектурное ограничение управляемого приложения, а не ошибка конфигурации.

Макеты хранятся в метаданных конфигурации, а доступ к метаданным в управляемом режиме есть только у серверного кода. Тонкий и веб-клиент не загружают метаданные целиком, поэтому платформа сознательно запрещает обращение к макетам из клиентского контекста. Обойти это ограничение нельзя, но можно спроектировать код так, чтобы макет получался на сервере, а результат передавался клиенту.

Ниже разобраны рабочие подходы: серверный вызов из формы, кэширование макета в реквизитах формы, передача через временное хранилище, а также особенности получения макета из общих макетов, макетов объектов и обработок. Отдельно рассмотрены типичные ошибки и ограничения по типам макетов.

Почему ПолучитьМакет не работает на клиенте

В управляемом приложении код формы делится на клиентский и серверный контексты. Директивы компиляции &НаКлиенте, &НаСервере, &НаСервереБезКонтекста определяют, где будет выполняться процедура. Методы ЭтотОбъект.ПолучитьМакет(), Обработки.ИмяОбработки.ПолучитьМакет() и ПолучитьОбщийМакет() требуют доступа к метаданным и потому компилируются только в серверном контексте.

Если разместить такой вызов в процедуре &НаКлиенте, при сохранении модуля формы или при обращении к процедуре возникнет ошибка вида «Процедура или функция с указанным именем не определена» либо сообщение о недопустимости вызова в данном контексте. Это не дефект конфигурации — платформа намеренно блокирует такие обращения, чтобы тонкий клиент не тянул за собой всю структуру метаданных.

Дополнительное ограничение: тип «ТабличныйДокумент» нельзя передавать между клиентом и сервером как параметр в обе стороны без ограничений — он сериализуется, но объёмные макеты создают заметный трафик. Поэтому при проектировании важно решить, что именно нужно клиенту: сам документ, его текстовое представление или только отдельные данные из макета.

Способ 1. Серверная процедура в модуле формы

Самый прямой вариант — создать в модуле формы серверную процедуру, которая получит макет и вернёт результат. Клиентская процедура вызывает её обычным образом; платформа сама выполнит серверный вызов.

&НаКлиенте

Процедура ПоказатьМакет(Команда)

ТабДок = ПолучитьМакетНаСервере();

ТабДок.Показать("Печатная форма");

КонецПроцедуры

&НаСервере

Функция ПолучитьМакетНаСервере()

Возврат РеквизитФормыВЗначение("Объект").ПолучитьМакет("МакетПечати");

КонецФункции

Обратите внимание на строку РеквизитФормыВЗначение("Объект"): в управляемой форме объекта (документа, справочника) сам объект существует только на сервере, и доступ к нему идёт через преобразование реквизита формы. Директива &НаСервере сохраняет доступ к данным формы, но требует передачи контекста формы на сервер, что делает вызов тяжелее.

Если макет нужен из общих макетов конфигурации, код на сервере ещё проще: ПолучитьОбщийМакет("ИмяМакета"). Такой вызов не требует контекста объекта, поэтому его можно разместить в процедуре &НаСервереБезКонтекста — это снизит накладные расходы на сериализацию формы.

bsl
&НаСервереБезКонтекста
Функция ПолучитьОбщийМакетНаСервере()
  Возврат ПолучитьОбщийМакет("МакетДанных");
КонецФункции

Способ 2. Передача макета через временное хранилище

Когда макет объёмный (например, двоичные данные с картинкой или большой текстовый файл), передавать его напрямую как возвращаемое значение не всегда удобно. Платформа предлагает механизм временного хранилища: сервер помещает значение в хранилище и возвращает клиенту только адрес — строку.

&НаСервереБезКонтекста

Функция ПоместитьМакетВХранилище()

Макет = ПолучитьОбщийМакет("ШаблонФайла");

Возврат ПоместитьВоВременноеХранилище(Макет, Новый УникальныйИдентификатор);

КонецФункции

На клиенте адрес используется для дальнейших действий: передачи в НачатьПомещениеФайлаНаСервер, выгрузки через ПолучитьФайл или чтения содержимого.

Этот способ особенно уместен для макетов типа «ДвоичныеДанные» и «ТекстовыйДокумент», когда клиенту нужно сохранить файл на диск. Табличный документ тоже можно поместить в хранилище, но чаще его передают напрямую и показывают методом Показать().

Способ 3. Кэширование макета при создании формы

Если макет нужен клиенту многократно (например, текстовый шаблон, который подставляется в поле при каждом нажатии кнопки), рационально получить его один раз — в обработчике ПриСозданииНаСервере — и сохранить в реквизите формы. Дальше клиент работает с реквизитом без повторных серверных вызовов.

Для текстовых макетов добавьте реквизит формы типа «Строка» неограниченной длины и заполните его на сервере:

&НаСервере

Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

ТекстШаблона = ПолучитьОбщийМакет("ШаблонПисьма").ПолучитьТекст();

КонецПроцедуры

Для табличных документов можно использовать реквизит формы типа «ТабличныйДокумент» — он отображается элементом формы «Поле табличного документа». Такой подход стандартно применяется в отчётных и печатных формах: макет формируется на сервере, а клиент только просматривает и редактирует результат.

Ограничение очевидно: кэширование подходит только для макетов, состав которых не меняется в течение жизни формы. Если макет зависит от параметров, введённых пользователем, потребуется повторный серверный вызов с передачей этих параметров.

Сравнение вариантов

Серверная процедура формы

Универсально, просто в реализации. Минус — серверный вызов при каждом обращении, для &НаСервере дополнительно передаётся контекст формы.

Временное хранилище

Подходит для двоичных данных и файлов. Требует контроля времени жизни хранилища и явного удаления данных.

Кэш в реквизите формы

Минимум серверных вызовов при многократном использовании. Не подходит для макетов, зависящих от меняющихся параметров.

Общий модуль с вызовом сервера

Удобно для переиспользуемой логики получения макетов из разных форм. Требует дисциплины в организации модулей.

Способ 4. Общий серверный модуль для повторного использования

Когда получение макета нужно в нескольких формах, логику выносят в общий модуль с флагами «Сервер» и «Вызов сервера». Клиентский код вызывает функцию общего модуля напрямую — платформа выполнит её на сервере и вернёт результат.

Требования к такому модулю: установленные свойства «Сервер» и «Вызов сервера», экспортные функции, параметры и возвращаемые значения только сериализуемых типов. Табличный документ, строка, адрес хранилища — допустимы; объекты типа «СправочникОбъект» передавать нельзя.

// Общий модуль РаботаСМакетами (Сервер, Вызов сервера)

Функция ПолучитьМакетОбработки(ИмяОбработки, ИмяМакета) Экспорт

Возврат Обработки[ИмяОбработки].ПолучитьМакет(ИмяМакета);

КонецФункции

Из клиентской процедуры обращение выглядит как обычный вызов: ТабДок = РаботаСМакетами.ПолучитьМакетОбработки("ЗагрузкаДанных", "Шаблон"). Это делает код чище и избавляет модули форм от дублирования серверных обёрток.

Особенности для разных типов макетов

Тип макета определяет, что именно можно передать клиенту и как с результатом работать. Табличный документ передаётся целиком и отображается в поле формы или показывается отдельным окном. Текстовый макет на сервере преобразуют в строку методом ПолучитьТекст() — строки передаются без ограничений.

Макеты типа «ДвоичныеДанные» (картинки, файлы-шаблоны) корректнее передавать через временное хранилище: двоичные данные как возвращаемое значение серверного вызова тоже допустимы, но хранилище даёт более предсказуемое поведение при больших размерах. Макеты типа «СхемаКомпоновкиДанных» и «МакетКомпоновкиДанных» на клиенте практически не используются — они нужны серверу для построения отчётов.

Внешние обработки и отчёты — отдельный случай. В управляемой форме внешней обработки получить её макет можно через ЭтотОбъект.ПолучитьМакет() только в серверном контексте формы обработки. Если обработка открыта в режиме тонкого клиента, действуют те же правила: серверная процедура, передача результата клиенту.

Типичные ошибки
01
Вызов ПолучитьМакет в процедуре &НаКлиенте — ошибка компиляции или выполнения; метод доступен только на сервере.
02
Использование &НаСервере вместо &НаСервереБезКонтекста там, где данные формы не нужны — лишняя сериализация формы и замедление вызова.
03
Попытка вернуть несериализуемый объект (например, объект справочника) вместо макета или его данных — ошибка передачи между клиентом и сервером.
04
Игнорирование очистки временного хранилища при частых вызовах — рост потребления памяти сервером.
05
Получение макета в цикле на каждую итерацию вместо однократного получения и кэширования — лишние серверные вызовы и заметные паузы в интерфейсе.

Проверка результата и диагностика проблем

После внедрения серверного вызова проверьте три вещи. Первое — компиляция модуля формы: конфигуратор не должен выдавать ошибок о недопустимом контексте. Второе — фактическое содержимое: выведите полученный табличный документ или строку и убедитесь, что это именно тот макет и его актуальная версия. Третье — поведение на тонком и веб-клиенте, если они используются: некоторые сценарии отладки на толстом клиенте маскируют ошибки контекста.

Если макет возвращается пустым, проверьте имя макета — оно чувствительно к точному написанию, и при опечатке платформа выдаст исключение «Макет не найден». Если форма работает медленно, посмотрите, не выполняется ли серверный вызов в цикле или при каждом событии формы; перенос получения макета в ПриСозданииНаСервере обычно решает проблему.

Контрольные точки

Как проверить результат

Компиляция модуля формы
Норма

Нет ошибок о контексте и неопределённых методах

Тревожный признак

Сообщения о недопустимости вызова ПолучитьМакет

Содержимое результата
Норма

Получен именно нужный макет, данные актуальны

Тревожный признак

Пустой документ или исключение «Макет не найден»

Скорость работы формы
Норма

Серверный вызов выполняется один раз или по явному действию пользователя

Тревожный признак

Вызовы повторяются в цикле или на каждое событие

Работа на тонком/веб-клиенте
Норма

Функциональность идентична толстому клиенту

Тревожный признак

Ошибки проявляются только на тонком клиенте

FAQ

Можно ли вообще как-то вызвать ПолучитьМакет прямо на клиенте?

Нет. Это архитектурное ограничение управляемого приложения: метаданные и макеты доступны только серверному коду. Единственный путь — серверный вызов из клиентской процедуры с передачей результата.

Что выбрать: &НаСервере или &НаСервереБезКонтекста?

Если для получения макета не нужны данные формы (типичный случай для общих макетов), используйте &НаСервереБезКонтекста — вызов будет легче, так как контекст формы не передаётся на сервер. Директива &НаСервере оправдана, когда нужен объект формы через РеквизитФормыВЗначение.

Как получить макет внешней обработки на клиенте?

Так же через серверную процедуру в модуле формы обработки: на сервере вызовите ЭтотОбъект.ПолучитьМакет("ИмяМакета") и верните результат клиенту. Для двоичных макетов удобнее поместить их во временное хранилище и вернуть адрес.

Можно ли передать табличный документ с сервера на клиент?

Да, табличный документ сериализуется и передаётся как возвращаемое значение серверной функции. На клиенте его можно показать методом Показать() или вывести в поле табличного документа. Учитывайте, что очень большие документы увеличат трафик между клиентом и сервером.

Как получить текстовый макет, чтобы отредактировать его на клиенте?

На сервере вызовите ПолучитьОбщийМакет("Имя").ПолучитьТекст() и верните строку. Клиент получит обычную строку, которую можно поместить в реквизит формы, отредактировать и при необходимости передать обратно на сервер для сохранения или обработки.

Итог

Что важно запомнить

Макет на клиенте получить нельзя — только через серверный вызов. Используйте &НаСервереБезКонтекста для общих макетов, временное хранилище для двоичных данных и кэширование в реквизитах формы при многократном использовании. Избегайте серверных вызовов в циклах и очищайте хранилище после использования.