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