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