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