Как передать данные в уже открытую форму обработки и активизировать ее в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки часто возникает задача взаимодействия между двумя обработками или документами: из одной формы подготавливаются данные и передаются в другую. Однако, если целевая форма уже открыта пользователем ранее, стандартный вызов открытия формы может либо создать дублирующее окно, либо не обновить данные в существующем, так как события инициализации при повторном вызове не срабатывают.

Разберем подробно механизмы платформы 1С:Предприятие, которые позволяют найти открытую форму, корректно дозаполнить в ней реквизиты (включая сложные типы, такие как дерево или таблица значений) и вывести окно на передний план.

Особенность повторного вызова формы и параметров открытия

Проанализируем поведение платформы при работе с методами ОткрытьФорму() и ПолучитьФорму(). Если форма с указанным ключом уникальности уже открыта в текущем сеансе, платформа не создает объект заново. Из этого следует важнейшее ограничение:

События ПриСозданииНаСервере и ПриОткрытии повторно не выполняются!

Если мы передаем структуру параметров в ОткрытьФорму() для уже работающей формы, эти параметры не приведут к автоматическому перезаполнению реквизитов через стандартные серверные обработчики создания. Для гарантированного обновления открытой формы необходимо использовать один из следующих подходов.

Способ 1. Использование механизма глобальных оповещений (рекомендуемый)

Рассмотрим наиболее универсальный и типовой подход для управляемого интерфейса. Он заключается в отправке оповещения с помощью процедуры Оповестить() и обработке этого события в целевой форме через ОбработкаОповещения.

Плюсы этого метода: вызывающей обработке не нужно знать внутреннюю структуру и состояние целевого окна, а форма корректно реагирует на события вне зависимости от того, была ли она открыта пользователем вручную или программно.

Разберем по шагам реализацию этого механизма:

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

Способ 2. Прямой вызов экспортного метода и метод Активизировать()

Посмотрим на ситуацию, когда вызывающий код получает ссылку на клиентский объект формы через ПолучитьФорму() или ОткрытьФорму(). Чтобы не открывать дубликатов, в параметр уникальности передается Ложь или фиксированный строковый ключ.

Для обновления данных в модуле целевой формы объявляется процедура с ключевым словом Экспорт, которая вызывается напрямую:

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

Способ 3. Передача сложных типов (ТаблицаЗначений, ДеревоЗначений)

Выясним причину, почему нельзя просто передать ТаблицаЗначений или ДеревоЗначений напрямую в параметры формы или процедуры на клиенте. В управляемом приложении эти типы не существуют на стороне тонкого клиента (они доступны только на сервере).

Для передачи таких структур между формами обязательно используется временное хранилище:

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

Поиск формы через коллекцию ОкнаКлиентскогоПриложения

В сложных сценариях интерфейса можно проанализировать открытые окна через глобальную коллекцию ОкнаКлиентскогоПриложения. Это позволяет перебрать все окна сеанса текущего пользователя, найти требуемое содержимое и программно сделать его активным:


&НаКлиенте
Процедура АктивизироватьОкноОбработки()
    
    Окна = ПолучитьОкна();
    Для Каждого ТекОкно Из Окна Цикл
        Содержимое = ТекОкно.ПолучитьСодержимое();
        // Проверяем, относится ли содержимое к нужной форме
        Если Содержимое <> Неопределено И Содержимое.ИмяФормы = "Обработка.ФормированиеМаршрута.Форма" Тогда
            ТекОкно.Активизировать();
            Прервать;
        КонецЕсли;
    КонецЦикла;
    
КонецПроцедуры

Таким образом, наиболее надежным и масштабируемым решением является комбинация помещения тяжелых структур во временное хранилище, отправки клиентского оповещения через Оповестить() и вызова метода Активизировать() у найденного экземпляра формы.

← На главную