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