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