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