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