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