Как передать данные из немодальной формы в форму-владелец при ее закрытии?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В современной разработке на платформе 1С:Предприятие 8.3 использование модальных окон считается устаревшим и зачастую невозможным (например, в веб-клиенте или при определенных настройках конфигурации). Часто возникает ситуация, когда нужно открыть вспомогательную форму немодально, выполнить в ней какие-то действия (например, заполнить таблицу или выбрать файл) и при закрытии вернуть результат в основную форму. Разберем подробно основные способы реализации этой задачи, проанализируем их плюсы и минусы, а также выясним, как избежать типичных ошибок.

Метод 1. Использование механизма «ОписаниеОповещения» и параметра закрытия

Это наиболее правильный и стандартный способ для управляемого приложения. Суть заключается в том, что при открытии формы мы заранее подготавливаем «адрес», по которому дочерняя форма отправит данные после своего закрытия. Рассмотрим этот процесс по шагам.

Шаг 1. В форме-владельце (откуда открываем)

Сначала мы создаем объект ОписаниеОповещения, указывая экспортную процедуру, которая примет данные. Затем используем метод ОткрытьФорму, передавая это оповещение в качестве одного из параметров.


&НаКлиенте
Процедура ОткрытьДочернююФорму(Команда)
    
    // Описываем, какую процедуру вызвать после закрытия
    Оповещение = Новый ОписаниеОповещения("ПослеЗакрытияДочернейФормы", ЭтотОбъект);
    
    // Открываем форму немодально
    // Параметр РежимОткрытияОкнаФормы.БлокироватьОкноВладельца сделает ее визуально модальной
    ОткрытьФорму("ОбщаяФорма.МояВспомогательнаяФорма", , ЭтаФорма, , , , Оповещение, РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);
    
КонецПроцедуры

&НаКлиенте
Процедура ПослеЗакрытияДочернейФормы(Результат, ДополнительныеПараметры) Экспорт
    
    Если Результат = Неопределено Тогда
        // Пользователь просто закрыл форму (нажал "крестик")
        Возврат;
    КонецЕсли;
    
    // Обрабатываем полученные данные
    Сообщить("Получены данные: " + Результат.Значение);
    
КонецПроцедуры

Шаг 2. В дочерней форме (которую закрываем)

В этой форме нам достаточно вызвать метод Закрыть(), передав в него данные, которые мы хотим вернуть. Платформа сама найдет описание оповещения и передаст данные в процедуру ПослеЗакрытияДочернейФормы.


&НаКлиенте
Процедура ЗавершитьРаботуИВернутьДанные(Команда)
    
    СтруктураРезультата = Новый Структура;
    СтруктураРезультата.Вставить("Значение", "Тестовые данные");
    СтруктураРезультата.Вставить("Таблица", Объект.ТабличнаяЧасть.Выгрузить());
    
    Закрыть(СтруктураРезультата);
    
КонецПроцедуры

Метод 2. Использование «ОповеститьОВыборе» и обработчика «ОбработкаВыбора»

Этот метод удобен, если дочерняя форма используется как форма выбора. Он автоматически связывается с обработчиком события ОбработкаВыбора формы-владельца.

Проанализируем ситуацию: когда в дочерней форме вызывается ОповеститьОВыборе(Данные), форма закрывается автоматически, а у владельца срабатывает стандартное событие. Чтобы это работало, при открытии формы в параметре Владелец должна быть указана основная форма (или элемент управления).

В форме-владельце:


&НаКлиенте
Процедура ОбработкаВыбора(ВыбранноеЗначение, ИсточникВыбора)
    // Данные придут сюда автоматически после вызова ОповеститьОВыборе в дочерней форме
    Если ТипЗнч(ВыбранноеЗначение) = Тип("Структура") Тогда
        // Заполняем реквизиты
    КонецЕсли;
КонецПроцедуры

В дочерней форме:


&НаКлиенте
Процедура КнопкаВыбрать(Команда)
    ДанныеДляПередачи = "Нужная строка или структура";
    ОповеститьОВыборе(ДанныеДляПередачи); // Форма закроется сама
КонецПроцедуры

Метод 3. Передача через «ВладелецФормы» и экспортные процедуры

Рассмотрим более прямой, но менее гибкий подход. Каждая форма имеет свойство ВладелецФормы. Если при открытии мы передали ЭтаФорма, то в дочернем окне мы можем напрямую обратиться к реквизитам или экспортным методам родителя, используя программное изменение форм.

Почему это может быть плохо? Проанализируем: если одна и та же вспомогательная форма вызывается из разных мест конфигурации, то во всех родительских формах должны быть одинаковые экспортные процедуры, иначе возникнет ошибка обращения к методу (полезно использовать инструмент для проверки вызовов экспортных процедур). Однако для простых задач это рабочее решение.

Пример в дочерней форме:


&НаКлиенте
Процедура ПередатьДанныеНапрямую()
    
    // Проверяем, что владелец установлен и у него есть нужный метод
    Попытка
        ВладелецФормы.ОбновитьДанныеНаОснованииВыбора(Объект.Ссылка);
        Закрыть();
    Исключение
        Сообщить("Не удалось передать данные владельцу напрямую.");
    КонецПопытки;
    
КонецПроцедуры

Передача больших объемов данных (Табличных частей)

Если вам нужно передать не одну строку, а целую ТабличнаяЧасть, прямая передача через параметры Закрыть() может быть неэффективной из-за сериализации данных на клиенте (для ресурсоемких операций лучше использовать конвейер фоновых задач). Выясним причину: при передаче коллекции между формами данные упаковываются и распаковываются, что при большом объеме строк может вызвать «зависание» интерфейса.

Оптимальный алгоритм:

  1. В дочерней форме на сервере помещаем таблицу во Временное хранилище (используя ПоместитьВоВременноеХранилище).
  2. Получаем Адрес этого хранилища (строка).
  3. Передаем этот Адрес в форму-владелец через Закрыть(Адрес).
  4. В форме-владельце (в процедуре оповещения) на сервере получаем данные по адресу через ПолучитьИзВременногоХранилища и заполняем свою таблицу.

Решение проблемы с блокировкой окна выбора файлов

В тексте обсуждения упоминалось, что модальный режим мешает открытию Excel или диалога выбора файлов. Разберем, как это обойти с помощью ОбработчикОжидания. Если вам жизненно необходимо открыть диалог сразу после открытия формы, используйте подключение обработчика ожидания на 0.1 секунды в событии ПриОткрытии. Это позволит форме полностью отрисоваться и «отпустить» поток интерфейса перед вызовом системного диалога ОС, что упростит отладку поведения системы.


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    // Подключаем однократный вызов
    ПодключитьОбработчикОжидания("ОткрытьФайлПослеОтрисовки", 0.1, Истина);
КонецПроцедуры

&НаКлиенте
Процедура ОткрытьФайлПослеОтрисовки()
    // Здесь код вызова диалога выбора файла (НачатьПомещениеФайла)
КонецПроцедуры

Важные нюансы и рекомендации

Таким образом, мы разобрали основные технические подходы к обмену данными между формами. Выбор конкретного метода зависит от сложности вашей задачи и требований к универсальности кода.

← На главную