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

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

Как из формы списка обратиться к модулю объекта в 1С

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

Задача обратиться из формы списка к коду модуля объекта встречается у разработчиков 1С постоянно: нужно выполнить проверку, пересчёт или служебную операцию для выбранного элемента, не открывая его форму. Сложность в том, что форма списка и модуль объекта живут в разных контекстах: форма работает на клиенте или в управляемом контексте формы, а модуль объекта исполняется на сервере и требует материализованного объекта в памяти.

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

Ниже разобраны рабочие способы: серверный вызов из формы списка, получение формы объекта через ПолучитьФорму(), перехват создания формы в модуле менеджера, а также типичные ошибки, из-за которых код не работает или работает медленно.

Почему из формы списка нельзя обратиться к модулю объекта напрямую

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

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

Основной способ: серверный вызов и ПолучитьОбъект()

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

&НаКлиенте

Процедура ВыполнитьДействие(Команда)

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

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

Возврат;

КонецЕсли;

ВыполнитьДействиеНаСервере(ТекущиеДанные.Ссылка);

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

&НаСервереБезКонтекста

Процедура ВыполнитьДействиеНаСервере(Ссылка)

Объект = Ссылка.ПолучитьОбъект();

Объект.МояЭкспортнаяПроцедура(); // процедура из модуля объекта

Объект.Записать();

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

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

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

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

Обращение через ПолучитьФорму() и модуль менеджера

Получение формы объекта

Если нужна не просто процедура модуля объекта, а именно форма элемента с её обработчиками, используют ПолучитьФорму(). Из формы списка можно открыть форму выбранного элемента, передав ключ:

&НаКлиенте

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

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

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

Возврат;

КонецЕсли;

ПараметрыФормы = Новый Структура("Ключ", ТекущиеДанные.Ссылка);

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

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

При таком открытии платформа создаёт объект на сервере, инициализирует форму, и в форме элемента доступен контекст объекта через реквизит формы (обычно Объект). Вызвать процедуру модуля объекта можно уже из модуля формы элемента — например, Объект.МояПроцедура() в серверном контексте формы.

Перехват через ОбработкаПолученияФормы

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

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

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

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

Сравнение вариантов

Модуль объекта + ПолучитьОбъект()

Подходит, когда логика опирается на данные конкретного элемента. Минус: объект целиком читается из базы, это затратно при массовой обработке.

Модуль менеджера

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

Общий серверный модуль

Универсальный вариант для служебной логики, принимающей ссылку параметром. Не привязан к жизненному циклу объекта.

Открытие формы элемента

Подходит, когда пользователь должен увидеть и подтвердить результат. Самый медленный вариант для массовых операций.

Массовая обработка выделенных строк

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

&НаСервереБезКонтекста

Процедура ОбработатьВыделенныеНаСервере(МассивСсылок)

Для Каждого Ссылка Из МассивСсылок Цикл

Объект = Ссылка.ПолучитьОбъект();

Объект.МояЭкспортнаяПроцедура();

Объект.Записать();

КонецЦикла;

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

После массовой записи форма списка не обновится автоматически. Вызовите на клиенте Элементы.Список.Обновить() или оповестите другие формы через ОповеститьОбИзменении(Ссылка) для каждой изменённой ссылки.

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

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

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

Типичные ошибки
01
Вызов процедуры через ссылку (Ссылка.Процедура()) — у ссылки нет методов модуля объекта, нужен ПолучитьОбъект()
02
Отсутствие Экспорт у процедуры модуля объекта — ошибка «метод не обнаружен» при внешнем вызове
03
Вызов ПолучитьОбъект() на клиенте в управляемом приложении — объектная модель недоступна на тонком клиенте
04
Забытый Записать() после изменения объекта — изменения теряются без сообщений
05
Серверный вызов в цикле на клиенте при массовой обработке — сотни обращений к серверу и зависание интерфейса
06
Изменение объекта без обновления списка — пользователь видит устаревшие данные и считает, что операция не сработала

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

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

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

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

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

Запись в журнале регистрации или сообщение появляется после команды

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

Команда отрабатывает молча, данных в журнале нет — проверьте Экспорт и серверный контекст

Сохранение изменений
Норма

После повторного открытия элемента реквизиты изменены

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

Значения старые — не вызван Записать() или запись завершилась с ошибкой

Отображение в списке
Норма

После Обновить() список показывает актуальные данные

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

Список показывает старые значения до ручного обновления

FAQ

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

Нет. Модуль объекта исполняется только в контексте созданного в памяти объекта, а создаёт его именно ПолучитьОбъект() (либо открытие формы элемента, либо СоздатьЭлемент/СоздатьДокумент для новых). Если создание объекта нежелательно, перенесите логику в модуль менеджера или общий модуль.

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

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

Как вызвать процедуру модуля объекта в обычном (неуправляемом) приложении?

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

Чем обращение к модулю менеджера отличается от обращения к модулю объекта?

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

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

Объявите параметры в экспортной процедуре модуля объекта и передайте значения при вызове: Объект.МояПроцедура(Параметр1, Параметр2). Сами значения соберите на клиенте и прокиньте через параметры серверной процедуры формы.

Безопасно ли вызывать Записать() объекта из формы списка, если элемент открыт у другого пользователя?

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

Итог

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

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