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