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