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

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

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

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

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

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

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

Как устроены процедуры формы и директивы компиляции

Каждая процедура и функция в модуле управляемой формы имеет директиву компиляции, определяющую, где она выполняется:

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

Если директиву не указать, в управляемой форме платформа подставит &НаСервере по умолчанию — это частая причина ошибок вида «Процедура или функция с указанным именем не определена» при вызове с клиента.

Вызов процедуры внутри той же формы

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

&НаКлиенте

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

ПересчитатьСуммуДокумента(); // клиентский вызов

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

&НаКлиенте

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

Объект.СуммаДокумента = Объект.Товары.Итог("Сумма");

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

Если логика требует обращения к базе данных (запрос, получение цены из регистра), клиентская процедура вызывает серверную:

&НаКлиенте

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

ЗаполнитьЦенуНаСервере();

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

&НаСервере

Процедура ЗаполнитьЦенуНаСервере()

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

// запрос к регистру цен

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

Обратите внимание: обращение к Элементы.Товары.ТекущиеДанные на сервере недопустимо — данные текущей строки нужно либо пересчитывать на клиенте, либо передавать идентификатор строки параметром в серверную процедуру.

Вызов серверной процедуры с клиента: правила и ограничения

Клиентская процедура может вызвать процедуру &НаСервере или &НаСервереБезКонтекста напрямую по имени — платформа сама выполнит серверный вызов. Ограничения:

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

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

ЕстьОстатки = ПроверитьОстаткиНаСервере(Объект.Склад);

Если Не ЕстьОстатки Тогда

ПоказатьПредупреждение(, "По складу нет свободных остатков");

КонецЕсли;

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

&НаСервере

Функция ПроверитьОстаткиНаСервере(Склад)

// запрос к регистру остатков

Возврат Истина;

КонецФункции

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

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

// В вызываемой форме:

&НаКлиенте

Процедура ОбработатьВыбор(ВыбранноеЗначение) Экспорт

Объект.Контрагент = ВыбранноеЗначение;

Модифицированность = Истина;

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

// В вызывающей форме:

ФормаДокумента = ПолучитьФорму("Документ.Заказ.ФормаОбъекта");

ФормаДокумента.ОбработатьВыбор(НовыйКонтрагент);

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

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

Форма-источник вызывает Оповестить("ИмяСобытия", Параметр, Источник), а форма-приёмник обрабатывает событие в стандартном обработчике ОбработкаОповещения:

&НаКлиенте

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

Если ИмяСобытия = "ЗаписанКонтрагент" Тогда

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

КонецЕсли;

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

Для возврата результата из модально открытой формы используйте ОписаниеОповещения и ВыполнитьОбработкуОповещения — это стандартный асинхронный паттерн вместо устаревших модальных вызовов.

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

Вызов процедуры через команду формы

Команда формы — штатный способ привязать кнопку к процедуре. В конфигураторе добавьте команду в дерево команд формы, перетащите её на форму, и платформа создаст обработчик вида &НаКлиенте Процедура ИмяКоманды(Команда).

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

&НаСервере

Процедура СоздатьКоманду()

НоваяКоманда = Команды.Добавить("ОбновитьДанные");

НоваяКоманда.Действие = "Подключаемый_ОбновитьДанные";

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

&НаКлиенте

Процедура Подключаемый_ОбновитьДанные(Команда)

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

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

Имя в свойстве Действие должно точно совпадать с именем процедуры в модуле формы, иначе получите ошибку «Процедура не обнаружена» при нажатии кнопки.

Типичные ошибки и их диагностика

Большинство проблем при вызове процедур формы сводится к нескольким повторяющимся причинам:

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

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

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

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

Процедура вызывается без ошибки компиляции
Норма

Модуль сохраняется, ошибок конфигуратора нет

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

Сообщение «Процедура или функция с указанным именем не определена»

Серверный вызов выполняется
Норма

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

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

Управление не попадает в процедуру — неверная директива или имя

Результат виден пользователю
Норма

Данные на форме обновились после вызова

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

Сервер всё посчитал, но клиент не обработал возвращаемое значение

FAQ

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

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

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

Чаще всего несовпадение контекстов: вызываете из &НаКлиенте процедуру без директивы (она по умолчанию серверная и недоступна), либо опечатка в имени, либо процедура находится в другом модуле и не экспортная. Проверьте директиву компиляции и ключевое слово Экспорт.

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

Используйте ПодключитьОбработчикОжидания("ИмяПроцедуры", Интервал, Однократно) на клиенте. Процедура-обработчик должна быть клиентской, экспортной и принимать не более одного параметра или ни одного. Отключается через ОтключитьОбработчикОжидания.

Чем &НаСервереБезКонтекста лучше &НаСервере?

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

Как передать результат из серверной процедуры обратно на клиент?

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

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

Нет. После закрытия объект формы уничтожается, и обращение к ней вызовет ошибку. Если нужно передать данные при закрытии — используйте Оповестить перед Закрыть() или возврат значения через Закрыть(Результат) с обработкой в описании оповещения.

Итог

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

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