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