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