Почему не закрывается форма документа при вызове метода ПолучитьФорму в 1С?

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

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

Проанализируем пример кода, вызывающий такую проблему:


Для Каждого Докум Из Метаданные.Документы Цикл 
    Для Каждого ТекФорма Из Докум.Формы Цикл 
        Форма = Документы[Докум.Имя].ПолучитьФорму(ТекФорма.Имя); 
        Если Форма.Открыта() Тогда 
            Сообщить("Закрываем форму: " + Докум.Имя + " " + ТекФорма.Имя); 
            Форма.Закрыть("ОК");
        КонецЕсли;
    КонецЦикла; 
КонецЦикла;

Выясним причину такого поведения платформы

Разберем по шагам, почему данный алгоритм отрабатывает для формы списка, но игнорирует открытые формы документов:

  1. Контекст менеджера и создание формы по умолчанию: Вызов Документы[ИмяДокумента].ПолучитьФорму(ИмяФормы) обращается к менеджеру объекта без передачи контекста конкретного существующего документа. В этом случае платформа возвращает экземпляр формы для нового (еще не созданного и не записанного) документа. Так как эта новая форма еще не выводилась пользователю, метод Форма.Открыта() закономерно возвращает Ложь.
  2. Ключ уникальности формы: Каждая форма объекта идентифицируется своим ключом уникальности (по умолчанию это ссылка ДокументСсылка или сам объект ДокументОбъект). Если у пользователя на экране открыт проведенный документ «Реализация товаров №15», то форма привязана именно к его ссылке. Попытка получить форму без указания ключа уникальности или ссылки возвращает совершенно другой экземпляр формы.
  3. Особенность формы списка: Основная форма списка менеджера по умолчанию создается в единственном экземпляре в рамках клиентского сеанса. Поэтому вызов ПолучитьФорму() для списка возвращает ссылку на уже существующую и открытую форму, позволяя ее закрыть.

Как решить задачу закрытия открытых окон

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

Вариант 1. Получение формы по ссылке или ключу уникальности

Если вам известна ссылка на конкретный открытый документ, форму необходимо получать с передачей ключа уникальности или ссылки в параметры:


// Получение формы конкретного документа
ПараметрыФормы = Новый Структура("Ключ", СсылкаНаДокумент);
ФормаДокумента = Документы[ИмяДокумента].ПолучитьФорму("ФормаДокумента", ПараметрыФормы, СсылкаНаДокумент);

Если ФормаДокумента.Открыта() Тогда
    ФормаДокумента.Закрыть();
КонецЕсли;

Передача ссылки в качестве ключа уникальности гарантирует, что платформа вернет именно ту форму, которая уже открыта у пользователя.

Вариант 2. Использование механизма оповещений (для типовых и дорабатываемых конфигураций)

Если требуется закрыть все открытые формы документов централизованно из внешней обработки или общего модуля, наиболее надежный способ — механизм оповещения открытых окон.

В вызывающем коде (например, в обработке):

Оповестить("ЗакрытьВсеФормыДокументов");

В формах документов (в процедуре-обработчике события ОбработкаОповещения):


Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
    Если ИмяСобытия = "ЗакрытьВсеФормыДокументов" Тогда
        ЭтаФорма.Закрыть();
    КонецЕсли;
КонецПроцедуры

Вариант 3. Штатный механизм для управляемого приложения

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


МассивОкон = ПолучитьОкна();
Для Каждого Окно Из МассивОкон Цикл
    // Пропускаем основное окно программы
    Если Не Окно.Основное Тогда
        Окно.Закрыть();
    КонецЕсли;
КонецЦикла;

Данный способ перебирает все открытые окна интерфейса и закрывает их без необходимости знать метаданные или ссылки объектов.

← На главную