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