Как передать таблицу значений в параметры ОткрытьФорму, если типовой код ожидает ТаблицуЗначений вместо ДанныеФормыКоллекция?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей IT и автоматизация бизнеса
← На главную

При разработке в среде 1С:Предприятие 8 на управляемых формах часто возникает задача открыть форму нового, еще не записанного документа (например, Документ.ПеремещениеТоваров) и заполнить его табличную часть данными, сформированными во внешней обработке или другой форме. Для этого стандартно используется метод ОткрытьФорму() с передачей структуры ЗначенияЗаполнения.

Однако на практике разработчики сталкиваются с серьезным препятствием: на клиенте табличные данные представлены типом ДанныеФормыКоллекция. Когда эти данные передаются на сервер в процедуру ОбработкаЗаполнения, платформа не преобразует их автоматически в полноценную ТаблицуЗначений. Если в типовом коде конфигурации (например, в УТ 11.4, КА или ERP) присутствует проверка колонок таблицы или обращение к методам, специфичным для ТЗ, система выдает ошибку: «Поле объекта не обнаружено (Колонки)».

В этой статье мы подробно разберем, почему возникает данная проблема, рассмотрим внутренние механизмы платформы 1С и изучим несколько надежных способов обхода этого ограничения без изменения типовой конфигурации.

Выясняем причину: почему возникает ошибка?

Проанализируем клиент-серверное взаимодействие в 1С. Объект ТаблицаЗначений является мутабельным типом данных. Это значит, что он может изменяться, и платформа принципиально запрещает передачу таких объектов напрямую между клиентом и сервером. На стороне клиента в управляемом интерфейсе вместо таблицы значений всегда используется ее проекция — ДанныеФормыКоллекция.

Когда мы вызываем код открытия формы на клиенте:


ПараметрыФормы = Новый Структура("ЗначенияЗаполнения", ПараметрыЗаполнения);
ОткрытьФорму("Документ.ПеремещениеТоваров.ФормаОбъекта", ПараметрыФормы);

Платформа передает структуру ПараметрыЗаполнения на сервер, где инициализируется новый объект документа и вызывается событие ОбработкаЗаполнения. Проблема заключается в том, что свойство Товары внутри структуры ДанныеЗаполнения на сервере сохраняет тип ДанныеФормыКоллекция (или преобразуется в массив структур).

Давайте посмотрим на пример типового кода в УТ 11, который приводит к ошибке:


Функция ДокументОснованиеПриЗаполнении(ДанныеЗаполнения)
    
    Если ТипЗнч(ДанныеЗаполнения) = Тип("Структура")
        И ДанныеЗаполнения.Свойство("Товары")
        И ДанныеЗаполнения.Товары.Колонки.Найти("ЗаказНаПеремещение") <> Неопределено Тогда
        
        Возврат ДанныеЗаполнения.Товары[0].ЗаказНаПеремещение;
        
    КонецЕсли;
    
    Возврат Неопределено;
    
КонецФункции

Поскольку ДанныеЗаполнения.Товары имеет тип ДанныеФормыКоллекция, попытка обратиться к свойству Колонки вызывает аварийное завершение работы программы. У этого типа просто нет коллекции Колонки, в отличие от ТаблицыЗначений.

Разберем по шагам, как решить эту проблему, сохранив типовую конфигурацию на поддержке.

Решение 1. Использование расширения для предобработки параметров (Рекомендуемое)

Самый элегантный и современный способ — использовать механизм расширений конфигурации. Мы можем перехватить управление непосредственно перед выполнением типовой процедуры ОбработкаЗаполнения в модуле объекта документа и преобразовать коллекцию в полноценную таблицу значений.

Для реализации этого решения выполним следующие действия:

  1. Создадим расширение конфигурации (если оно еще не создано в вашей базе).
  2. Добавим в расширение документ ПеремещениеТоваров и его модуль объекта.
  3. Создадим в модуле объекта обработчик со стандартной аннотацией &Перед для процедуры ОбработкаЗаполнения.

Напишем следующий код в расширении:


&Перед("ОбработкаЗаполнения")
Процедура Расш_ПередОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
    
    Если ТипЗнч(ДанныеЗаполнения) = Тип("Структура") 
        И ДанныеЗаполнения.Свойство("Товары") Тогда
        
        // Проверяем, если пришла коллекция форм, конвертируем ее в ТЗ
        Если ТипЗнч(ДанныеЗаполнения.Товары) = Тип("ДанныеФормыКоллекция") Тогда
            
            // Преобразуем ДанныеФормыКоллекция в полноценную Таблицу Значений
            ТаблицаТоваров = ДанныеЗаполнения.Товары.Выгрузить();
            
            // Подменяем свойство в структуре заполнения на настоящую ТЗ
            ДанныеЗаполнения.Вставить("Товары", ТаблицаТоваров);
            
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

Как это работает: Метод Выгрузить() у объекта типа ДанныеФормыКоллекция работает на сервере и возвращает полноценную ТаблицуЗначений со всей структурой колонок и данными. Мы подменяем элемент структуры ДанныеЗаполнения перед тем, как управление перейдет к типовому коду. В результате типовая функция успешно находит свойство Колонки и отрабатывает без ошибок.

Решение 2. Передача данных через Временное Хранилище в модуль формы

Если по каким-то причинам вы не хотите затрагивать модуль объекта документа через расширение (например, правила корпоративной разработки запрещают доработку бизнес-логики проведения и заполнения объектов), мы можем перенести логику в модуль управляемой формы документа.

Проанализируем этот сценарий по шагам:

Шаг 1. Формирование и отправка данных из вызывающей формы (обработки)

В модуле вызывающей формы на сервере мы помещаем подготовленную таблицу значений во временное хранилище и передаем полученный адрес на клиент:


&НаСервере
Функция ПодготовитьДанныеВоВременномХранилище()
    
    // Создаем и заполняем таблицу значений
    ТабТовары = Новый ТаблицаЗначений;
    ТабТовары.Колонки.Добавить("Номенклатура");
    ТабТовары.Колонки.Добавить("Количество");
    ТабТовары.Колонки.Добавить("ЗаказНаПеремещение");
    
    // Заполняем строки...
    НоваяСтрока = ТабТовары.Добавить();
    НоваяСтрока.Номенклатура = Справочники.Номенклатура.НайтиПоКоду("000001");
    НоваяСтрока.Количество = 10;
    
    // Помещаем ТЗ в хранилище, привязывая к Уникальному Идентификатору формы
    Возврат ПоместитьВоВременноеХранилище(ТабТовары, УникальныйИдентификатор);
    
КонецФункции

&НаКлиенте
Процедура ОткрытьДокументПеремещения()
    
    АдресХранилища = ПодготовитьДанныеВоВременномХранилище();
    
    // Передаем адрес хранилища через параметры формы под произвольным ключом
    ПараметрыФормы = Новый Структура;
    ПараметрыФормы.Вставить("АдресВременногоХранилищаТоваров", АдресХранилища);
    
    ОткрытьФорму("Документ.ПеремещениеТоваров.ФормаОбъекта", ПараметрыФормы);
    
КонецПроцедуры

Шаг 2. Прием данных в расширении формы документа

Добавим в наше расширение форму документа ПеремещениеТоваров (обычно это ФормаОбъекта). Создадим обработчик события ПриСозданииНаСервере с аннотацией &После:


&После("ПриСозданииНаСервере")
Процедура Расш_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Проверяем наличие нашего уникального параметра
    Если Параметры.Свойство("АдресВременногоХранилищаТоваров") Тогда
        
        // Получаем ТЗ из временного хранилища
        ТаблицаИзХранилища = ПолучитьИзВременногоХранилища(Параметры.АдресВременногоХранилищаТоваров);
        
        Если ТипЗнч(ТаблицаИзХранилища) = Тип("ТаблицаЗначений") Тогда
            
            // Напрямую заполняем табличную часть формы документа
            Объект.Товары.Загрузить(ТаблицаИзХранилища);
            
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

Этот способ полностью изолирует логику заполнения внутри контекста формы, не затрагивая транзакционные механизмы создания объекта на сервере базы данных.

Интересный лайфхак: Как создать Таблицу Значений прямо на клиенте?

В ходе обсуждения на форуме был упомянут очень интересный и малоизвестный лайфхак платформы 1С. Обычно попытка написать на клиенте Новый ТаблицаЗначений вызывает ошибку компиляции кода. Однако платформу можно обойти, используя объект ОписаниеТипов:


ОписаниеТЗ = Новый ОписаниеТипов("ТаблицаЗначений");
ТабЗначений = ОписаниеТЗ.ПривестиЗначение();

Проанализируем этот прием: Действительно, этот код успешно скомпилируется и выполнится в тонком клиенте. Переменная ТабЗначений получит тип ТаблицаЗначений. Вы даже сможете добавлять в нее строки и колонки на клиенте.

Но внимание! Данный лайфхак не решает проблему автора темы. Как только вы попытаетесь передать эту «клиентскую» таблицу значений в параметры метода ОткрытьФорму() или в любой другой серверный вызов, платформа выдаст стандартное исключение:

«Ошибка передачи данных между клиентом и сервером. Значение недопустимого типа (мутабельное значение)».

Это связано с тем, что физическая природа таблицы значений на клиенте не меняется — она остается сложным мутабельным объектом, не подлежащим сериализации для передачи по каналам связи между клиентским приложением и сервером приложений 1С.

Резюме

При передаче табличных данных в параметры заполнения форм документов всегда учитывайте специфику типов данных управляемого интерфейса:

Используя предложенные нами решения, вы сможете сохранить конфигурацию полностью типовой, обеспечив стабильную работу программы и простоту последующих обновлений.

← На главную