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