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