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