К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как получить открытую форму документа в 1С

Как получить уже открытую форму документа в 1С: поиск по уникальному идентификатору, ПолучитьФорму, Оповестить и работа с параметрами. Примеры кода на встроенном языке.

Задача получить уже открытую форму документа возникает, когда нужно обновить данные на форме извне, передать в неё новые параметры или убедиться, что пользователь не открыл один и тот же документ дважды. В управляемом приложении 1С нет привычного из обычных форм перебора окон — вместо этого используется поиск формы по ключевым параметрам через метод ПолучитьФорму() либо механизм оповещений.

Ключевая идея проста: платформа сама ведёт реестр открытых форм и сопоставляет их по набору параметров, с которыми форма была создана. Если вызвать ПолучитьФорму() с теми же параметрами, что использовались при открытии, система вернёт существующий экземпляр вместо создания нового. Для документов таким ключом обычно служит параметр Ключ, содержащий ссылку на объект.

Ниже разобраны основные способы: получение формы конкретного документа по ссылке, поиск среди открытых окон, передача данных через оповещения и типичные ошибки, из-за которых вместо существующей формы открывается дубликат.

Как платформа идентифицирует открытую форму

Каждая управляемая форма в 1С при создании получает набор параметров и уникальность, определяемую ключом уникальности. Для формы объекта документа ключом уникальности служит ссылка на документ. Пока форма с таким ключом открыта, повторный вызов ПолучитьФорму() с тем же ключом не создаст новый экземпляр, а вернёт ссылку на уже существующий.

Это принципиально отличается от обычного приложения, где можно было перебрать окна через Окна или АктивноеОкно(). В управляемом интерфейсе такого прямого перебора нет, и попытки найти форму «в лоб» через окна не работают — нужно опираться на параметры формы.

Получение формы документа по ссылке через ПолучитьФорму()

Основной рабочий вариант — вызов ПолучитьФорму() с именем формы и структурой параметров. Если документ уже открыт, вы получите существующую форму и сможете, например, активировать её или прочитать данные.

bsl
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("Ключ", ДокументСсылка);

ФормаДокумента = ПолучитьФорму("Документ.РеализацияТоваровУслуг.Форма.ФормаДокумента", ПараметрыФормы);

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

Метод Открыта() позволяет различить две ситуации: форма уже отображается пользователю или была только что создана программно. Если форма открыта — достаточно активировать её, чтобы поднять окно на передний план. Если нет — откройте её стандартно.

Обратите внимание: имя формы должно точно соответствовать конфигурации. Если у документа назначена основная форма, можно использовать короткое имя Документ.ИмяДокумента.ФормаОбъекта — платформа подставит назначенную форму автоматически.

Проверка, открыта ли форма, без её создания

Недостаток ПолучитьФорму() в том, что при отсутствии открытого экземпляра метод создаст новую форму, даже если вы не собирались её показывать. Когда нужно только проверить факт открытия, применяют другой приём — перебор открытых окон приложения через ПолучитьОкна() и анализ содержимого.

bsl
Функция ФормаДокументаОткрыта(ДокументСсылка)
    Окна = ПолучитьОкна();
    Для Каждого Окно Из Окна Цикл
        Если Окно.ПолучитьСодержимое() <> Неопределено
            И ТипЗнч(Окно.ПолучитьСодержимое()) = Тип("УправляемаяФорма") Тогда
            Форма = Окно.ПолучитьСодержимое();
            Если Форма.ИмяФормы = "Документ.РеализацияТоваровУслуг.Форма.ФормаДокумента"
                И Форма.Объект.Ссылка = ДокументСсылка Тогда
                Возврат Истина;
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
    Возврат Ложь;
КонецФункции

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

Учитывайте, что обращение к Форма.Объект возможно только для форм объектов (документов, справочников). У произвольных форм такого реквизита может не быть, поэтому перед сравнением ссылки полезно проверять имя формы.

Передача данных в открытую форму через оповещения

Когда цель — не получить форму, а сообщить ей о событии (например, что связанный документ изменился), правильнее использовать Оповестить(). Открытая форма получает сообщение через обработчик ОбработкаОповещения и сама решает, как отреагировать.

bsl
// В коде, инициирующем событие:
Оповестить("ИзмененСвязанныйДокумент", Новый Структура("Ссылка", ДокументСсылка), ЭтотОбъект);

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

Плюс подхода в том, что отправителю не нужно знать, открыта ли форма и сколько таких форм существует: сообщение получат все подписанные экземпляры. Минус — форма должна заранее содержать обработчик, то есть механизм работает только для форм, код которых вы контролируете.

Для стандартного сценария «обновить список после записи» конфигурации обычно уже содержат типовые оповещения: ОповеститьОбИзменении(Ссылка) заставляет открытые списки и формы объекта перечитать данные без дополнительного кода.

Порядок действий при выборе способа
  1. 1
    Определите цель: активировать форму, проверить факт открытия или передать данные
  2. 2
    Для активации используйте ПолучитьФорму() с параметром Ключ и метод Активизировать()
  3. 3
    Для проверки без создания формы переберите окна через ПолучитьОкна()
  4. 4
    Для передачи данных внедрите Оповестить() и ОбработкаОповещения
  5. 5
    Проверьте результат: форма активировалась без создания дубликата

Сравнение способов и ограничения

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

СпособКогда подходитОграничение
ПолучитьФорму() с КлючАктивировать или открыть форму конкретного документаСоздаёт новую форму, если открытой нет
ПолучитьОкна() и переборТолько проверить факт открытияКлиентский контекст, только текущий сеанс
Оповестить()Передать событие всем открытым формамНужен обработчик в форме-приёмнике
ОповеститьОбИзменении()Обновить списки и формы после записиТолько стандартная реакция — перечитывание

Отдельное ограничение — тонкий и веб-клиент. Код с перебором окон и обращением к элементам формы должен выполняться в клиентском контексте; на сервере открытые формы недоступны по определению, потому что интерфейс живёт на клиенте.

Сравнение вариантов

ПолучитьФорму + Активизировать

Лучший вариант, чтобы поднять уже открытое окно документа; побочный эффект — создание формы, если её не было

Перебор ПолучитьОкна()

Подходит для строгой проверки без побочных эффектов; не работает на сервере и между сеансами

Оповестить + ОбработкаОповещения

Гибкий обмен данными между формами; требует доработки модуля формы-приёмника

Типичные ошибки и как их избежать

Самая частая проблема — вместо существующей формы открывается дубликат. Причина почти всегда в несовпадении параметров: при первом открытии передали дополнительные параметры, а при поиске — только Ключ, или наоборот. Ключ уникальности учитывает весь набор параметров, влияющих на уникальность.

Вторая ошибка — попытка получить форму на сервере. Вызов ПолучитьФорму() в серверном контексте приведёт к ошибке или непредсказуемому поведению: формы существуют только на клиенте. Серверная логика должна завершаться возвратом данных, а работа с формами — выполняться в клиентских процедурах.

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

Типичные ошибки
01
Несовпадение параметров при повторном ПолучитьФорму() — платформа создаёт дубликат окна вместо возврата существующего
02
Вызов ПолучитьФорму() на сервере — ошибка выполнения, так как формы существуют только на клиенте
03
Обращение к Форма.Объект без проверки типа формы — падение кода на формах без реквизита Объект
04
Ожидание, что Оповестить() дойдёт до форм других пользователей — оповещения работают только внутри сеанса

Проверка результата и границы безопасной работы

Признак корректной работы: при повторном выполнении кода количество открытых окон документа не растёт, а существующее окно активируется. Если после вызова появляется второе окно того же документа — сверяйте набор параметров при первом и повторном открытии.

Изменения вносите сначала в копии информационной базы или на тестовом стенде. Ошибки в коде работы с формами редко портят данные, но неаккуратный вызов ЭтотОбъект.Прочитать() в обработчике оповещения может затереть несохранённые изменения пользователя на форме — предусмотрите проверку Модифицированность перед перечитыванием.

Контрольные точки

Как проверить результат

Количество окон документа после повторного вызова
Норма

Остаётся одно окно, оно активируется

Тревожный признак

Открывается второй экземпляр той же формы

Поведение при закрытой форме
Норма

Форма открывается заново без ошибок

Тревожный признак

Ошибка обращения к несуществующему экземпляру

Реакция формы на оповещение
Норма

Данные обновляются, несохранённые изменения не теряются

Тревожный признак

Форма перечитывается и затирает ввод пользователя

Итог

Что важно запомнить

Открытую форму документа получают через ПолучитьФорму() с параметром Ключ — платформа вернёт существующий экземпляр при совпадении параметров. Для проверки без создания формы перебирайте окна, для передачи данных используйте Оповестить(). Весь код работы с формами выполняется только на клиенте.

Частые вопросы

Можно ли получить форму документа, открытую другим пользователем?

Нет. Открытые формы существуют только в клиентском сеансе конкретного пользователя. Для контроля одновременной работы используйте механизм блокировок данных при редактировании — платформа сама сообщит, что объект редактируется другим пользователем.

Почему ПолучитьФорму() возвращает новую форму, хотя документ уже открыт?

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

Как закрыть открытую форму документа программно?

Получите форму через ПолучитьФорму() с тем же ключом и вызовите метод Закрыть(). Если на форме есть несохранённые изменения, платформа задаст пользователю вопрос о сохранении — полностью подавить его штатными средствами нельзя, и это защита от потери данных.

Работает ли перебор окон в веб-клиенте?

Метод ПолучитьОкна() доступен в веб-клиенте, но структура окон может отличаться от тонкого клиента. Перед обращением к содержимому окна всегда проверяйте, что оно не равно Неопределено и имеет тип УправляемаяФорма.

Чем отличается Оповестить() от ОповеститьОбИзменении()?

Оповестить() отправляет произвольное сообщение с произвольными параметрами, которое обрабатывается в ОбработкаОповещения. ОповеститьОбИзменении() — стандартный сигнал о записи объекта: открытые формы списков и объектов реагируют на него автоматически, без дополнительного кода.

Можно ли получить открытую форму из фонового задания?

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