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