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

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

Как программно вызвать событие формы в 1С

Как программно вызвать событие формы в 1С: методы ПодключитьОбработчикОжидания, ВызватьИсключение, обходные приёмы для управляемых и обычных форм с примерами кода.

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

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

Почему событие нельзя «вызвать» напрямую и что делать вместо этого

В платформе 1С:Предприятие события формы (ПриОткрытии, ПриИзменении, Нажатие и другие) генерируются системой. Разработчик не может заставить форму «подумать», что пользователь нажал кнопку или изменил поле. Но это и не требуется: вся полезная логика находится в обработчике, а обработчик — обычная процедура в модуле формы.

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

Прямой вызов обработчика из модуля той же формы

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

&НаКлиенте

Процедура ТоварыКоличествоПриИзменении(Элемент)

ПересчитатьСтроку(Элементы.Товары.ТекущиеДанные);

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

&НаКлиенте

Процедура КомандаПересчитатьВсе(Команда)

// Имитация события для каждой строки

Для Каждого Строка Из Объект.Товары Цикл

ПересчитатьСтроку(Строка);

КонецЦикла;

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

Если обработчик ожидает параметр Элемент, а вызов идёт не от элемента формы, передайте реальный элемент через Элементы.ИмяПоля либо Неопределено — но тогда внутри обработчика обязательна проверка на Неопределено, иначе получите ошибку обращения к свойству. Это частая причина падения кода при программном вызове.

Учитывайте директивы компиляции. Процедура &НаСервере недоступна из клиентского контекста напрямую — потребуется серверный вызов, что в управляемом приложении означает обращение к серверу и связанные накладные расходы. По возможности размещайте общую логику так, чтобы контексты вызова совпадали.

Выделение общей процедуры вместо вызова обработчика

Более надёжная практика — не вызывать обработчик события напрямую, а вынести его содержимое в отдельную процедуру с понятным именем. Обработчик события остаётся тонкой обёрткой, а логика доступна отовсюду без подмены параметров события.

&НаКлиенте

Процедура ЦенаПриИзменении(Элемент)

РассчитатьСуммуСтроки();

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

&НаКлиенте

Процедура РассчитатьСуммуСтроки()

ТекущиеДанные = Элементы.Товары.ТекущиеДанные;

Если ТекущиеДанные = Неопределено Тогда

Возврат;

КонецЕсли;

ТекущиеДанные.Сумма = ТекущиеДанные.Цена * ТекущиеДанные.Количество;

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

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

Если в типовой конфигурации нужно переиспользовать логику обработчика, ищите в модуле формы процедуры с префиксами вроде «Рассчитать», «Обновить», «Заполнить» — в типовых решениях логика обычно уже вынесена из обработчиков в отдельные методы, и вызывать нужно именно их.
ПЗ
Практическое замечание

Отложенный и периодический вызов через обработчики ожидания

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

&НаКлиенте

Процедура ПриОткрытии(Отказ)

// Однократный вызов через 0,1 секунды после открытия

ПодключитьОбработчикОжидания("ПослеОткрытияФормы", 0.1, Истина);

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

&НаКлиенте

Процедура ПослеОткрытияФормы()

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

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

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

Минимальный практический интервал — десятые доли секунды. Слишком частые вызовы (меньше 0,1 с) не дают выигрыша, но нагружают клиентский сеанс. Для фоновых серверных вычислений вместо обработчиков ожидания правильнее использовать фоновые задания с доставкой результата через Оповестить().

Порядок действий для отложенного вызова
  1. 1
    Создайте в модуле формы клиентскую процедуру без параметров с нужной логикой
  2. 2
    В нужном месте вызовите ПодключитьОбработчикОжидания с именем процедуры строкой, интервалом и признаком однократности
  3. 3
    Убедитесь, что имя процедуры указано точно и процедура экспортная не требуется — достаточно обычной клиентской
  4. 4
    При необходимости отключите обработчик через ОтключитьОбработчикОжидания с тем же именем
  5. 5
    Проверьте выполнение, добавив временный вывод сообщения или точку останова

Вызов логики формы извне: из другой формы или общего модуля

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

&НаКлиенте

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

ФормаСписка = ПолучитьФорму("Справочник.Номенклатура.ФормаСписка");

ФормаСписка.Открыть();

ФормаСписка.ОбновитьОтборПоУсловию(МойОтбор); // экспортная процедура формы

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

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

Для обновления списков есть стандартные имена оповещений: ОповеститьОбИзменении(Ссылка) заставит открытые списки и формы связанных объектов перечитать данные. Это штатный способ «вызвать событие» обновления у всех заинтересованных форм разом, не зная об их существовании.

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

Прямой вызов обработчика

Быстро и просто внутри одного модуля; требует подмены параметров события и хрупок при рефакторинге

Отдельная процедура с логикой

Самый надёжный вариант для повторного использования; требует рефакторинга существующего кода

ПодключитьОбработчикОжидания

Подходит для отложенного и периодического выполнения; работает только на клиенте

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

Стандарт для межформенного взаимодействия; требует согласования имён событий между формами

Особенности обычных форм и внешних обработок

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

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

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

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

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

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

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

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

Выполнение процедуры
Норма

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

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

Точка не срабатывает — проверить имя, контекст, директиву

Данные формы
Норма

Реквизиты и таблицы пересчитаны, изменения видны на форме

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

Код выполнен, но форма показывает старые значения

Обработчик ожидания
Норма

Процедура вызывается нужное число раз с заданным интервалом

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

Выполняется бесконечно после закрытия или не вызывается вовсе

Межформенное оповещение
Норма

ОбработкаОповещения получает нужное имя события

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

Имя события не совпадает или форма-приёмник закрыта

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

Можно ли программно вызвать событие ПриОткрытии формы?

Напрямую заставить форму повторно сгенерировать ПриОткрытии нельзя. Вынесите логику инициализации в отдельную процедуру и вызывайте её из ПриОткрытии и из любого другого места, где требуется повторная инициализация.

Сработает ли обработчик ПриИзменении, если изменить реквизит программно?

Нет. События интерактивных изменений генерируются только действиями пользователя. После программного присвоения значения вызовите расчётную процедуру явно — это стандартная практика.

Как вызвать процедуру формы из общего модуля?

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

Почему ПодключитьОбработчикОжидания не вызывает мою процедуру?

Частые причины: имя процедуры указано с ошибкой (передаётся строкой и не контролируется компилятором), процедура имеет параметры (обработчик ожидания должен быть без параметров), либо процедура расположена в серверном контексте, а механизм работает только на клиенте.

Как обновить открытый список после записи объекта программно?

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

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

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

Итог

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

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