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