Нередко при разработке сервисных обработок (например, аналога функции «Закрыть все окна») разработчики сталкиваются с ситуацией: при обходе метаданных и попытке программно получить форму метод Открыта() возвращает Ложь для документов, хотя визуально окно документа открыто на экране. При этом форма списка того же документа успешно находится и закрывается.
Проанализируем пример кода, вызывающий такую проблему:
Для Каждого Докум Из Метаданные.Документы Цикл
Для Каждого ТекФорма Из Докум.Формы Цикл
Форма = Документы[Докум.Имя].ПолучитьФорму(ТекФорма.Имя);
Если Форма.Открыта() Тогда
Сообщить("Закрываем форму: " + Докум.Имя + " " + ТекФорма.Имя);
Форма.Закрыть("ОК");
КонецЕсли;
КонецЦикла;
КонецЦикла;
Разберем по шагам, почему данный алгоритм отрабатывает для формы списка, но игнорирует открытые формы документов:
Документы[ИмяДокумента].ПолучитьФорму(ИмяФормы) обращается к менеджеру объекта без передачи контекста конкретного существующего документа. В этом случае платформа возвращает экземпляр формы для нового (еще не созданного и не записанного) документа. Так как эта новая форма еще не выводилась пользователю, метод Форма.Открыта() закономерно возвращает Ложь.ДокументСсылка или сам объект ДокументОбъект). Если у пользователя на экране открыт проведенный документ «Реализация товаров №15», то форма привязана именно к его ссылке. Попытка получить форму без указания ключа уникальности или ссылки возвращает совершенно другой экземпляр формы.ПолучитьФорму() для списка возвращает ссылку на уже существующую и открытую форму, позволяя ее закрыть.В обычном приложении 1С отсутствует штатная глобальная коллекция всех произвольно открытых окон, если ссылки на открытые документы заранее неизвестны. Рассмотрим корректные подходы к решению этой задачи в зависимости от режима работы и архитектуры конфигурации.
Если вам известна ссылка на конкретный открытый документ, форму необходимо получать с передачей ключа уникальности или ссылки в параметры:
// Получение формы конкретного документа
ПараметрыФормы = Новый Структура("Ключ", СсылкаНаДокумент);
ФормаДокумента = Документы[ИмяДокумента].ПолучитьФорму("ФормаДокумента", ПараметрыФормы, СсылкаНаДокумент);
Если ФормаДокумента.Открыта() Тогда
ФормаДокумента.Закрыть();
КонецЕсли;
Передача ссылки в качестве ключа уникальности гарантирует, что платформа вернет именно ту форму, которая уже открыта у пользователя.
Если требуется закрыть все открытые формы документов централизованно из внешней обработки или общего модуля, наиболее надежный способ — механизм оповещения открытых окон.
В вызывающем коде (например, в обработке):
Оповестить("ЗакрытьВсеФормыДокументов");
В формах документов (в процедуре-обработчике события ОбработкаОповещения):
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
Если ИмяСобытия = "ЗакрытьВсеФормыДокументов" Тогда
ЭтаФорма.Закрыть();
КонецЕсли;
КонецПроцедуры
Если задача решается на платформе 1С:Предприятие 8.3 в режиме управляемого приложения, для обхода окон предусмотрен специальный клиентский метод ПолучитьОкна():
МассивОкон = ПолучитьОкна();
Для Каждого Окно Из МассивОкон Цикл
// Пропускаем основное окно программы
Если Не Окно.Основное Тогда
Окно.Закрыть();
КонецЕсли;
КонецЦикла;
Данный способ перебирает все открытые окна интерфейса и закрывает их без необходимости знать метаданные или ссылки объектов.