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