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