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