Как передать данные между немодальными обработками в 1С 7.7 без глобальных переменных?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При разработке сложных интерфейсных решений в платформе 1С:Предприятие 7.7 нередко возникает задача организации взаимодействия двух и более форм. Классический сценарий: из основной обработки открывается подчиненная форма для подбора или уточнения данных, пользователь производит выбор, и результат должен вернуться в исходное окно. При модальном открытии (команда ОткрытьФормуМодально()) выполнение кода в вызывающей форме приостанавливается, и результат легко вернуть через параметр закрытия. Однако модальный режим блокирует всю систему, что не всегда удобно пользователю.

При переходе к немодальным формам разработчики сталкиваются с вопросом: как передавать информацию «туда и обратно» без объявления громоздких глобальных переменных в модуле конфигурации, и почему предопределенная процедура ПриПовторномОткрытии() не срабатывает при простом переключении окон мышью? Разберем особенности работы платформы 1С 7.7 и рассмотрим эффективные варианты реализации двустороннего обмена данными.

Почему не срабатывает процедура ПриПовторномОткрытии()?

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

Платформа 1С 7.7 вызывает событие ПриПовторномОткрытии() исключительно программно — в момент выполнения функции ОткрытьФорму() по отношению к объекту, форма которого уже открыта на экране. Если пользователь просто переключается между открытыми окнами кликом мыши или системными клавишами, событие ПриПовторномОткрытии() не возникает ни при каких обстоятельствах. В штатной функциональности платформы событий перехвата фокуса (активации окна) нет.

Решение 1: Передача контекста вызывающей формы (рекомендуемый способ)

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

Разберем пошаговый алгоритм реализации:

  1. В модуле первой обработки (которая инициирует вызов) описываем процедуру открытия и передаем ключевое слово Контекст в качестве параметра. Также объявляем экспортную процедуру, которая будет принимать результат:

// В модуле формы первой обработки (Обработка1)

// Процедура для приема данных из второй обработки
Процедура ПринятьДанныеИзВторой(ДанныеРезультата) Экспорт
    Сообщить("Получены данные: " + ДанныеРезультата);
    // Обработка полученных значений
КонецПроцедуры

// Вызов второй обработки
Процедура ОткрытьПодчиненнуюОбработку()
    // Передаем собственный контекст во вторую форму
    ОткрытьФорму("Обработка.Обработка2", Контекст);
КонецПроцедуры
  1. Во второй обработке при открытии считываем полученный контекст и сохраняем его в локальную переменную модуля. При выполнении действий (например, по нажатию кнопки) вызываем нужную экспортную процедуру первой формы:

// В модуле формы второй обработки (Обработка2)
Перем КонтекстПервой;

Процедура ПриОткрытии()
    // Проверяем, передан ли контекст
    Если ТипЗначения(Форма.Параметр) = 100 Тогда
        КонтекстПервой = Форма.Параметр;
    КонецЕсли;
КонецПроцедуры

Процедура КнопкаВернутьДанные()
    // Проверяем, что первая форма все еще открыта (тип 100)
    Если ТипЗначения(КонтекстПервой) = 100 Тогда
        КонтекстПервой.ПринятьДанныеИзВторой("ВыбранноеЗначение");
        // При необходимости обновляем форму на экране
        КонтекстПервой.Форма.Обновить();
    Иначе
        Предупреждение("Исходная форма была закрыта!");
    КонецЕсли;
КонецПроцедуры

Важный нюанс: тип значения открытой формы в 1С 7.7 равен 100 (групповой контекст). Если пользователь закроет первое окно, переменная перестанет указывать на рабочий контекст (тип изменится на 0). Проверка Если ТипЗначения(КонтекстПервой) = 100 защитит код от критических ошибок времени выполнения при обращении к закрытому окну.

Решение 2: Использование ссылочных объектов (СписокЗначений или ТаблицаЗначений)

Если нет необходимости напрямую дергать процедуры чужого модуля, можно использовать особенность передачи сложных объектов по ссылке. Созданный в первой обработке СписокЗначений или ТаблицаЗначений передается через параметр во вторую форму. Обе формы в этом случае работают с единой областью памяти.

Посмотрим на пример организации взаимодействия:


// Модуль первой обработки
Перем ОбщийБуфер;

Процедура ОткрытьОкноВыбора()
    ОбщийБуфер = СоздатьОбъект("СписокЗначений");
    ОбщийБуфер.ДобавитьЗначение("КлючевойПараметр", "Ключ");
    
    // Передаем ссылку на объект
    ОткрытьФорму("Обработка.Обработка2", ОбщийБуфер);
КонецПроцедуры

Во второй обработке мы модифицируем этот же объект:


// Модуль второй обработки
Процедура ЗаписатьРезультат()
    Если ТипЗначенияСтр(Форма.Параметр) = "СписокЗначений" Тогда
        Форма.Параметр.Установить("Результат", "НайденноеЗначение");
    КонецЕсли;
КонецПроцедуры

Любые изменения, сделанные во второй форме, мгновенно видны в первой обработке в объекте ОбщийБуфер без необходимости синхронизации.

Решение 3: Принудительный программный вызов ПриПовторномОткрытии()

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

Разберем, как это работает:


// Во второй обработке по кнопке или действию пользователя
Процедура ОтправитьДанныеВПервую()
    ПараметрыВозврата = "РезультатРасчета";
    // Повторный вызов не дублирует форму, а передает управление в ПриПовторномОткрытии
    ОткрытьФорму("Обработка.Обработка1", ПараметрыВозврата);
КонецПроцедуры

В этом случае платформа активизирует существующее окно первой обработки и выполнит процедуру:


// В модуле первой обработки
Процедура ПриПовторномОткрытии(Парам)
    Сообщить("Сработало повторное открытие с данными: " + Парам);
КонецПроцедуры

Обратите внимание: если при первичном вызове обработки использовался модификатор множественного открытия через решетку (к примеру, ОткрытьФорму("Обработка.Моя#1")), то и повторный вызов обязан содержать аналогичный идентификатор после #, иначе откроется новое окно вместо передачи параметров в существующее.

← На главную