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