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