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