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