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