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