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