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