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