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