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