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