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

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

Как запустить процедуру из другой формы в 1С

Как вызвать процедуру другой формы в 1С 8.3: Экспорт, Оповестить, владелец формы и общие модули. Примеры кода, типичные ошибки и проверка результата.

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

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

Ниже разобраны все основные способы: прямой вызов экспортной процедуры через полученную форму, обращение к форме-владельцу, механизм Оповестить/ОбработкаОповещения, а также альтернатива через общие модули, которая часто оказывается архитектурно правильнее.

Какие способы вызова существуют и когда какой выбирать

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

Сравнение способов вызова

Прямой вызов Экспорт-процедуры

Быстро и наглядно, но требует ссылки на открытую форму; при закрытой форме вызовет ошибку.

Через ВладелецФормы

Идеально для связки «список — элемент», но работает только при правильно переданном владельце.

Оповестить / ОбработкаОповещения

Слабая связность между формами, но слушатель должен сам реализовать обработчик, а отправитель не знает, сработал ли вызов.

Общий модуль

Архитектурно чисто для логики без привязки к форме, но не подходит, если нужно менять элементы и реквизиты конкретной формы.

Подготовка: делаем процедуру доступной извне

Чтобы процедуру формы можно было вызвать извне, она должна быть объявлена с ключевым словом Экспорт. Без него процедура остаётся приватной для модуля формы, и попытка внешнего вызова завершится ошибкой «Процедура или функция с указанным именем не определена».

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

&НаКлиенте

Процедура ОбновитьДанныеСписка(ПараметрыОтбора) Экспорт

ОбновитьДанныеСпискаНаСервере(ПараметрыОтбора);

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

&НаСервере

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

// серверная логика: запрос, перезаполнение таблицы

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

Прямой вызов через ссылку на форму

Если форма-источник сама открыла целевую форму или получила на неё ссылку, вызов сводится к обращению вида СсылкаНаФорму.ИмяПроцедуры(Параметры). Получить ссылку можно несколькими путями: сохранить результат ОткрытьФорму() в переменную, передать ЭтаФорма в параметры открываемой формы или найти форму через окна приложения.

Типичный пример: форма А открывает форму Б и передаёт себя, чтобы Б могла вернуть результат. В форме Б ссылка сохраняется в реквизит, и в нужный момент вызывается экспортная процедура формы А.

// Форма А: открываем форму Б и передаём себя

&НаКлиенте

Процедура ОткрытьПодбор(Команда)

ПараметрыФормы = Новый Структура("ФормаИсточник", ЭтаФорма);

ОткрытьФорму("Обработка.ПодборТоваров.Форма.ФормаПодбора",

ПараметрыФормы, ЭтаФорма);

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

// Форма Б: при создании сохраняем ссылку

&НаСервере

Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

Если Параметры.Свойство("ФормаИсточник") Тогда

ФормаИсточник = Параметры.ФормаИсточник; // реквизит формы

КонецЕсли;

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

Вызов процедуры формы-владельца

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

Если при открытии третьим параметром указать ЭтаФорма или уникальный идентификатор, владелец установится автоматически. Дальше вызов выглядит просто: ЭтаФорма.ВладелецФормы.МояПроцедура(Параметры). Обязательно проверяйте, что ВладелецФормы не равен Неопределено — форму могли открыть и независимо, без владельца.

&НаКлиенте

Процедура ВыбратьИЗакрыть(Команда)

Если ЭтаФорма.ВладелецФормы <> Неопределено Тогда

ЭтаФорма.ВладелецФормы.ОбработатьВыборТовара(ВыбранныйТовар);

КонецЕсли;

Закрыть();

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

Порядок настройки вызова через владельца
  1. 1
    В форме-владельце объявите экспортную клиентскую процедуру-приёмник.
  2. 2
    При открытии подчинённой формы передайте владельца: ОткрытьФорму(ИмяФормы, Параметры, ЭтаФорма).
  3. 3
    В подчинённой форме проверьте ЭтаФорма.ВладелецФормы на Неопределено.
  4. 4
    Вызовите ВладелецФормы.ИмяПроцедуры(Параметры) в нужный момент.
  5. 5
    Проверьте, что форма-владелец ещё открыта — иначе оберните вызов в Попытка/Исключение.

Вызов через оповещения: Оповестить и ОбработкаОповещения

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

По сути, это и есть «запуск процедуры другой формы», только инвертированный: вы не вызываете конкретную форму, а публикуете событие, и нужная форма сама запускает свою внутреннюю процедуру. Имя события — произвольная строка; договоритесь о соглашении по именам, например «Запись_Номенклатура» или «ИзмененГрафикРаботы», чтобы не словить чужие оповещения.

// Форма-источник после записи элемента:

&НаКлиенте

Процедура ПослеЗаписи(ПараметрыЗаписи)

Оповестить("Запись_Номенклатура", СсылкаНаЭлемент, ЭтаФорма);

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

// Форма-приёмник (например, динамический список):

&НаКлиенте

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

Если ИмяСобытия = "Запись_Номенклатура" Тогда

ОбновитьСтрокуСписка(Параметр); // своя процедура формы

КонецЕсли;

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

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

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

Альтернатива: вынос логики в общий модуль

Если процедура, которую вы хотите «запустить из другой формы», по сути не работает с элементами и реквизитами той формы, а выполняет прикладную логику (запрос к базе, расчёт, проверка), правильнее разместить её в общем модуле. Тогда обе формы вызывают её напрямую: МойОбщийМодуль.ВыполнитьРасчет(Параметры), без всяких ссылок на формы.

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

Проверка результата и типичные ошибки

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

Контрольные точки

Как проверить результат

Вызов дошёл до приёмника
Норма

Точка останова в процедуре-приёмнике срабатывает

Тревожный признак

Ошибка «процедура не определена» или тишина — нет Экспорт или неверная ссылка на форму

Передача параметров
Норма

В приёмнике параметры заполнены ожидаемыми значениями

Тревожный признак

Параметры Неопределено — структура параметров собрана с другими ключами

Поведение при закрытой форме
Норма

Проверка на Неопределено или Попытка/Исключение отрабатывает штатно

Тревожный признак

Исключение прерывает работу пользователя, если форма-владелец уже закрыта

Типичные ошибки
01
Забыли слово Экспорт — вызов падает с ошибкой «процедура не определена», хотя в модуле формы она есть.
02
Вызов серверной процедуры формы с клиента другой формы — такой вызов невозможен; нужна клиентская экспортная обёртка.
03
Обращение к ВладелецФормы без проверки на Неопределено — ошибка при независимом открытии формы.
04
Вызов процедуры уже закрытой формы без Попытка/Исключение — пользователь получает необработанное исключение.
05
Совпадающие имена событий в Оповестить у разных механизмов — формы реагируют на чужие оповещения.

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

Можно ли вызвать процедуру формы, которая сейчас закрыта?

Нет. Форма существует как объект только пока открыта. Если форма закрыта, ссылка на неё недействительна. Варианты решения: открыть форму заново с параметрами, перенести нужную логику в общий модуль или сохранить данные в базе и обработать их при следующем открытии формы.

Чем отличается Оповестить от ОповеститьОбИзменении?

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

Как вернуть результат из открытой формы обратно в форму-источник?

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

Почему возникает ошибка «Процедура или функция с указанным именем не определена»?

Три основные причины: у процедуры нет ключевого слова Экспорт; несовпадение директив компиляции (клиент вызывает серверную процедуру формы); опечатка в имени. Проверьте объявление процедуры в модуле целевой формы и контекст вызова.

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

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

Что лучше для связи форм списка и элемента в типовой конфигурации?

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

Итог

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

Экспортная клиентская процедура + ссылка на открытую форму (ВладелецФормы или сохранённая ссылка) — базовый способ прямого вызова. Для слабосвязанных форм используйте Оповестить/ОбработкаОповещения, а логику без привязки к форме выносите в общие модули. Всегда проверяйте ссылку на Неопределено и защищайте вызов от ситуации «форма уже закрыта».