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