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