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

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

Как из модуля объекта обратиться к форме в 1С

Как из модуля объекта обратиться к форме в 1С: ЭтаФорма, ЭтотОбъект, УправляемаяФорма, Оповестить. Примеры кода, ограничения, типичные ошибки и FAQ.

В модуле объекта (документа, справочника, обработки) напрямую «дотянуться» до формы нельзя — объект и форма живут в разных контекстах, и платформа намеренно разделяет их. Однако задача решаема: в зависимости от режима (обычное или управляемое приложение) и цели (обновить данные, показать сообщение, закрыть форму) используются разные механизмы — от ПолучитьФорму() до оповещений.

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

Почему из модуля объекта нельзя напрямую обратиться к форме

Модуль объекта — это серверный контекст. В управляемом приложении код объекта исполняется на сервере, где нет ни экрана, ни элементов формы, ни свойств вроде Элементы или ЭтаФорма. Даже если вы напишете обращение к форме, компилятор или исполнение выдадут ошибку «Переменная не определена» либо «Метод недоступен в данном контексте».

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

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

Способ 1. Получить форму объекта через ПолучитьФорму()

Если задача — открыть форму объекта из кода (например, при интерактивной работе в толстом клиенте или при создании нового элемента), используется метод ПолучитьФорму(). В обычном приложении он доступен прямо из модуля объекта:

// Модуль объекта, обычное приложение

ФормаОбъекта = ЭтотОбъект.ПолучитьФорму("ФормаОбъекта");

ФормаОбъекта.Открыть();

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

В управляемом приложении ПолучитьФорму() вызывается глобально, но только в клиентском контексте. Из серверного модуля объекта управляемой формы этот путь недоступен — там работают оповещения и параметры открытия.

Способ 2. Оповестить() — штатный механизм связи с формой

В управляемом приложении стандартный способ «достучаться» из любого кода до открытых форм — оповещения. В модуле объекта (в клиентском вызове) или в общем модуле вызывается Оповестить(), а форма, которой нужно отреагировать, подписывается через ОбработкаОповещения:

// Код, который инициирует событие

Оповестить("ОбновитьСписокДокументов", ЭтотОбъект.Ссылка, ЭтотОбъект);

// Модуль формы списка

&НаКлиенте

Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)

Если ИмяСобытия = "ОбновитьСписокДокументов" Тогда

Элементы.Список.Обновить();

КонецЕсли;

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

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

Ограничение метода: Оповестить() работает только на клиенте. Из серверной процедуры модуля объекта вызвать его нельзя — нужно вернуть управление на клиент и оповестить оттуда, либо передать признак через параметр записи.

Способ 3. Передать форму как параметр в объект

Если форма сама вызывает серверную процедуру объекта и хочет получить результат обратно, правильный путь — не объект тянется к форме, а форма передаёт в вызов всё необходимое и забирает результат. Типовой шаблон:

// Модуль формы

&НаСервере

Процедура ВыполнитьОбработкуНаСервере()

ОбъектДанные = РеквизитФормыВЗначение("Объект");

ОбъектДанные.ЗаполнитьПоДаннымФормы(ПараметрыЗаполнения);

ЗначениеВРеквизитФормы(ОбъектДанные, "Объект");

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

Здесь РеквизитФормыВЗначение() превращает данные формы в объект, с ним работает модуль объекта, а ЗначениеВРеквизитФормы() возвращает результат обратно на форму. Это единственный корректный способ «взаимодействия» объекта и формы на сервере — через обмен данными, а не через ссылки на форму.

Тот же приём применяется и в обработчиках объекта: если в ПередЗаписью нужно показать пользователю вопрос, этого делать нельзя — вместо этого установите Отказ = Истина и параметр, а форма по нему покажет диалог на клиенте.

Порядок действий для управляемого приложения
  1. 1
    Определите, где исполняется код: на сервере или на клиенте
  2. 2
    Для уведомления форм используйте Оповестить() или ОповеститьОбИзменении()
  3. 3
    Для передачи данных на сервер — РеквизитФормыВЗначение() и обратно ЗначениеВРеквизитФормы()
  4. 4
    Логику работы с элементами формы разместите в модуле формы
  5. 5
    Проверьте поведение при закрытой форме объекта — код не должен падать

Способ 4. Обращение к форме в обычном приложении

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

// Модуль объекта, обычное приложение

Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)

Форма = ЭтотОбъект.ПолучитьФорму();

Если Форма.Открыта() Тогда

Форма.ОбновитьДополнительныеДанные();

КонецЕсли;

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

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

Типичные ошибки и как их избежать

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

Ещё одна ошибка — бесконтрольное создание форм: каждый вызов ПолучитьФорму() с новым ключом уникальности порождает новый экземпляр, что приводит к утечкам памяти и «дублям» окон. Переиспользуйте форму через ключ уникальности или проверяйте, открыта ли она.

Типичные ошибки
01
Обращение к ЭлементыФормы из модуля объекта — переменная недоступна в этом контексте
02
Вызов Оповестить() в серверной процедуре — метод доступен только на клиенте
03
ПолучитьФорму() без проверки Открыта() — ошибка при программной записи объекта
04
Диалоги (Вопрос, Предупреждение) в ПередЗаписью объекта — блокируют пакетную запись и обмены
05
Создание новой формы вместо поиска открытой — дубли окон и лишний расход памяти

Как выбрать подходящий способ

Выбор зависит от трёх факторов: режим приложения, контекст исполнения (клиент/сервер) и цель обращения. Если нужно просто обновить открытые списки после записи — хватит ОповеститьОбИзменении(). Если нужна реакция конкретной формы — своё событие через Оповестить() и ОбработкаОповещения. Если требуется передать данные в объект и получить результат — обмен через РеквизитФормыВЗначение().

Маршрут решения

Как выбрать действие

Нужно обновить открытые списки после записи объектаВызовите ОповеститьОбИзменении(Ссылка) на клиенте
Нужна реакция конкретной формы на событие объектаИспользуйте Оповестить() с уникальным именем события и ОбработкаОповещения в форме
Нужно выполнить метод объекта с данными формы на сервереПреобразуйте данные через РеквизитФормыВЗначение() и верните результат через ЗначениеВРеквизитФормы()
Работаете в обычном приложении и форма точно открытаИспользуйте ЭтотОбъект.ПолучитьФорму() с проверкой Открыта()

Проверка результата

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

Полезно временно добавить в ОбработкаОповещения вывод имени события через Сообщить() — так вы увидите, доходит ли оповещение и с какими параметрами. После отладки отладочные сообщения удалите.

Итог

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

Прямого обращения из модуля объекта к форме не существует по архитектурным причинам. В управляемом приложении используйте оповещения и обмен данными через РеквизитФормыВЗначение, в обычном — ПолучитьФорму() с проверкой Открыта(). Интерфейсную логику держите в модуле формы.

Частые вопросы

Можно ли из модуля объекта вызвать процедуру модуля формы?

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

Чем ЭтаФорма отличается от ЭтотОбъект?

ЭтаФорма — свойство модуля формы, ссылающееся на саму форму и её элементы. ЭтотОбъект — свойство модуля объекта, ссылающееся на данные объекта (реквизиты, табличные части). Они существуют в разных модулях и не взаимозаменяемы.

Почему Оповестить() не срабатывает в процедуре с директивой &НаСервере?

Метод Оповестить() доступен только в клиентском контексте. Вынесите вызов в клиентскую процедуру: серверная процедура возвращает нужные данные, а клиентская после её завершения вызывает Оповестить().

Как из ПередЗаписью объекта задать вопрос пользователю?

Напрямую — никак, модальные вызовы в обработчиках записи запрещены и опасны. Установите Отказ = Истина и запомните причину, а форма после неудачной записи покажет вопрос на клиенте и при согласии повторит запись с нужным параметром.

Как найти уже открытую форму конкретного документа?

Штатного поиска по всем окнам в управляемом приложении нет. Практичные варианты: ПолучитьФорму() с ключом уникальности по ссылке (платформа сама активирует существующую форму при открытии) либо собственный реестр открытых форм через оповещения о создании и закрытии.