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

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

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

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

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

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

Все примеры приведены для управляемых форм (режим «Такси»), актуальных для большинства современных конфигураций на платформе 8.3. Код работает в клиентских и клиент-серверных процедурах форм.

Открытие формы с передачей параметров

Самый частый способ «обратиться» к другой форме — открыть её и передать параметры через функцию ОткрытьФорму(). Параметры доступны в открываемой форме через свойство Параметры в обработчике ПриСозданииНаСервере.

// В форме-источнике (клиент)

ПараметрыФормы = Новый Структура;

ПараметрыФормы.Вставить("Контрагент", КонтрагентСсылка);

ПараметрыФормы.Вставить("Период", НачалоМесяца(ТекущаяДата()));

ОткрытьФорму("Справочник.ДоговорыКонтрагентов.Форма.ФормаСписка",

ПараметрыФормы, ЭтотОбъект, Новый УникальныйИдентификатор);

// В открываемой форме (сервер)

&НаСервере

Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

Если Параметры.Свойство("Контрагент") Тогда

ОтборКонтрагент = Параметры.Контрагент;

// дальнейшая логика: установка отбора, заполнение реквизитов

КонецЕсли;

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

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

Получение результата из открытой формы через оповещение

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

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

// Форма-источник

&НаКлиенте

Процедура ПодобратьТовар(Команда)

Оповещение = Новый ОписаниеОповещения("ПослеВыбораТовара", ЭтотОбъект);

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

Оповещение, РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);

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

&НаКлиенте

Процедура ПослеВыбораТовара(Результат, ДопПараметры) Экспорт

Если Результат <> Неопределено Тогда

Объект.Товар = Результат;

КонецЕсли;

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

Чтобы результат вернулся, в форме выбора нужно вызвать Закрыть(ВыбранноеЗначение). Если форма закрыта крестиком без передачи значения, в обработчик придёт Неопределено — это нужно учитывать в проверке.

Вариант 2: ОповеститьОВыборе

Этот способ стандартен для форм подбора. Форма-подчинённая вызывает ОповеститьОВыборе(Значение), а в форме-владельце срабатывает предопределённый обработчик ОбработкаВыбора:

// В форме выбора

&НаКлиенте

Процедура СписокВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)

ОповеститьОВыборе(ВыбраннаяСтрока);

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

// В форме-владельце

&НаКлиенте

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

Объект.Номенклатура = ВыбранноеЗначение;

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

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

ОписаниеОповещения + Закрыть()

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

ОповеститьОВыборе

Стандарт для форм выбора и подбора. Работает только при указанном владельце формы, результат попадает в ОбработкаВыбора.

Глобальное оповещение Оповестить()

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

Оповещения между уже открытыми формами

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

// Форма-источник: рассылает оповещение

&НаКлиенте

Процедура ПослеЗаписи(ПараметрыЗаписи)

Оповестить("ЗаписанНовыйДокумент", Объект.Ссылка, ЭтотОбъект);

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

// Форма-приёмник: реагирует на оповещение

&НаКлиенте

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

Если ИмяСобытия = "ЗаписанНовыйДокумент" Тогда

Элементы.Список.Обновить();

КонецЕсли;

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

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

Стандартные события платформы тоже приходят в этот обработчик: "Запись_ИмяДокумента", "ИзменениеДанных" и другие. Проверяйте ИмяСобытия строго по равенству, чтобы не реагировать на чужие оповещения.

Типичные ошибки
01
Вызов Оповестить() до того, как форма-приёмник открыта — оповещение уходит «в пустоту», данные теряются. Решение: передавать данные параметрами при открытии или открывать форму заранее.
02
Использование общего имени события вроде «Обновить» — срабатывают чужие обработчики типовой конфигурации, форма обновляется в неподходящий момент.
03
Попытка обратиться к Элементы другой формы напрямую — в управляемом приложении это невозможно, код либо не скомпилируется, либо упадёт с ошибкой.
04
Забытый четвёртый параметр уникальности в ОткрытьФорму() — при повторном вызове открываются дубликаты одной и той же формы.

Обращение к уже открытой форме через коллекцию окон

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

&НаКлиенте

Процедура НайтиИАктивироватьФорму()

ОкнаПриложения = ПолучитьОкна();

Для Каждого Окно Из ОкнаПриложения Цикл

Если Окно.ПолучитьСодержимое() <> Неопределено Тогда

ФормаОкна = Окно.ПолучитьСодержимое();

Если ТипЗнч(ФормаОкна) = Тип("УправляемаяФорма")

И СтрНайти(ФормаОкна.ИмяФормы, "ФормаСписка") > 0 Тогда

Окно.Активизировать();

КонецЕсли;

КонецЕсли;

КонецЦикла;

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

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

Передача данных через владельца формы

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

// В подчинённой форме

&НаКлиенте

Процедура ПередатьДанныеРодителю(Команда)

Если ВладелецФормы <> Неопределено Тогда

ОповеститьОВыборе(ВыбранноеЗначение);

// либо через оповещение с указанием источника

КонецЕсли;

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

Проверка ВладелецФормы <> Неопределено обязательна: форму могут открыть напрямую из интерфейса, без владельца, и тогда обращение к владельцу завершится ошибкой. Это особенно важно для форм, которые используются и как самостоятельные, и как формы подбора.

Передача данных между формами через сервер

Когда данные нужно подготовить на сервере и передать в другую форму, применяют временное хранилище. Данные помещаются в хранилище на сервере, а адрес передаётся в открываемую форму:

&НаСервере

Функция ПодготовитьДанныеПодбора()

ТаблицаТоваров = ПолучитьТаблицуТоваров(); // запрос к данным

Возврат ПоместитьВоВременноеХранилище(ТаблицаТоваров,

ЭтотОбъект.УникальныйИдентификатор);

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

&НаКлиенте

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

АдресДанных = ПодготовитьДанныеПодбора();

ПараметрыФормы = Новый Структура("АдресДанных", АдресДанных);

ОткрытьФорму("Обработка.ПодборТоваров.Форма.Форма", ПараметрыФормы, ЭтотОбъект);

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

// В открываемой форме

&НаСервере

Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

Если Параметры.Свойство("АдресДанных") Тогда

Данные = ПолучитьИзВременногоХранилища(Параметры.АдресДанных);

// заполнение таблицы формы

КонецЕсли;

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

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

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

Проверка результата и отладка взаимодействия форм

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

&НаКлиенте

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

Сообщить("Событие: " + ИмяСобытия); // удалить после отладки

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

В конфигураторе полезен точечный поиск: найдите все места вызова Оповестить с нужным именем события, чтобы убедиться, что оповещение отправляется именно оттуда, откуда ожидается. Если обработчик не срабатывает — чаще всего причина в опечатке в имени события или в том, что форма-приёмник ещё не создана.

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

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

Параметры дошли до открытой формы
Норма

В ПриСозданииНаСервере Параметры.Свойство() возвращает Истина, значения корректны

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

Свойство отсутствует — проверьте имя ключа в структуре и имя в Свойство()

Оповещение получено
Норма

ОбработкаОповещения срабатывает, ИмяСобытия совпадает с отправленным

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

Обработчик молчит — форма-приёмник закрыта или имя события отличается

Результат выбора возвращён
Норма

В обработчик оповещения пришло ожидаемое значение

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

Пришло Неопределено — форма закрыта без Закрыть(Значение) или без ОповеститьОВыборе

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

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

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

Почему ОбработкаОповещения не срабатывает, хотя Оповестить вызывается?

Наиболее частые причины: форма-приёмник в момент вызова ещё не создана, имя события в отправителе и приёмнике отличается (включая регистр букв), либо оповещение отправляется на сервере, а обработчик находится в клиентском контексте формы. Метод Оповестить работает только на клиенте.

Как открыть форму и запретить открытие её дубликата?

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

Как передать таблицу значений в другую форму?

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

Чем отличается Оповестить от ОповеститьОВыборе?

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

Работают ли эти механизмы в обычных формах?

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

Итог

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

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