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