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