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