Как программно удалить или отключить отбор в СКД

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Работа с отборами в системе компоновки данных (СКД) часто вызывает вопросы у разработчиков, особенно когда дело касается управляемых форм. Распространенная ситуация: программист пишет код для удаления отбора, но визуально на форме ничего не меняется, или отчет продолжает формироваться с учетом старых данных. В этой статье мы подробно разберем, почему так происходит, и изучим правильные методы управления отборами.

Разбираем причину проблемы: иерархия настроек

Первое, что нам необходимо понять — это архитектура хранения настроек в КомпоновщикНастроек. В СКД существует два уровня настроек:

  1. Общие настройки (КомпоновщикНастроек.Настройки): это структура, заданная в схеме компоновки по умолчанию или программно измененная база.
  2. Пользовательские настройки (КомпоновщикНастроек.ПользовательскиеНастройки): это те значения, которые пользователь видит и редактирует непосредственно на форме отчета (флажки, поля ввода, условия).

Важный нюанс: если элемент отбора включен в состав пользовательских настроек (у него установлен соответствующий флаг в конфигураторе или программно), то значения из ПользовательскиеНастройки имеют абсолютный приоритет над общими настройками. Именно поэтому попытки очистить КомпоновщикНастроек.Настройки.Отбор.Элементы часто не дают видимого результата — форма продолжает отображать данные из пользовательского набора. Для детального разбора механизмов связи элементов управляемой формы и настроек отчета можно использовать публикацию по стыковке элементов формы и пользовательских настроек СКД.

Метод 1. Полная очистка всех отборов

Если перед нами стоит задача полностью очистить все установленные фильтры, мы должны избегать удаления элементов в цикле Для Каждого. Рассмотрим типичную ошибку начинающих разработчиков:


// ОШИБОЧНЫЙ КОД
Для Каждого Стр Из КомпоновщикНастроек.Настройки.Отбор.Элементы Цикл
    КомпоновщикНастроек.Настройки.Отбор.Элементы.Удалить(Стр);
КонецЦикла;

Проблема этого кода заключается в том, что при удалении первого элемента индексы всех последующих смещаются, и цикл «проскакивает» объекты. Чтобы сделать это правильно, проанализируем два корректных способа:

  1. Использование метода Очистить(), который разом удаляет все элементы коллекции.
  2. Удаление с конца коллекции с помощью счетчика.

Однако, помня о приоритете пользовательских настроек, нам нужно воздействовать именно на них. Если мы хотим сбросить всё до состояния «по умолчанию», лучше всего использовать метод ЗагрузитьНастройки():


// Сброс настроек к заводским (из схемы СКД)
Схема = Отчет.СхемаКомпоновкиДанных; 
КомпоновщикНастроек.ЗагрузитьНастройки(Схема.НастройкиПоУмолчанию);

Метод 2. Поиск и отключение конкретного отбора по полю

Чаще всего нам нужно не удалить все отборы, а очистить конкретное поле (например, «Склад» или «Контрагент»). Для этого нам нужно найти элемент в Настройки, получить его ИдентификаторПользовательскойНастройки и по этому идентификатору найти соответствующий элемент в ПользовательскиеНастройки.

Рассмотрим алгоритм поиска по шагам:


// 1. Определяем поле, которое ищем
ПолеСклад = Новый ПолеКомпоновкиДанных("Склад");

// 2. Ищем элемент в основных настройках
ЭлементНастройки = Неопределено;
Для Каждого Элемент Из КомпоновщикНастроек.Настройки.Отбор.Элементы Цикл
    Если ТипЗнч(Элемент) = Тип("ЭлементОтбораКомпоновкиДанных") 
        И Элемент.ЛевоеЗначение = ПолеСклад Тогда
        ЭлементНастройки = Элемент;
        Прервать;
    КонецЕсли;
КонецЦикла;

// 3. Если нашли, меняем связанную пользовательскую настройку
Если ЭлементНастройки <> Неопределено Тогда
    ID = ЭлементНастройки.ИдентификаторПользовательскойНастройки;
    ПользовательскийЭлемент = КомпоновщикНастроек.ПользовательскиеНастройки.Элементы.Найти(ID);
    
    Если ПользовательскийЭлемент <> Неопределено Тогда
        // Отключаем использование (снимаем галочку)
        ПользовательскийЭлемент.Использование = Ложь;
        // Или очищаем значение, если нужно оставить галочку
        ПользовательскийЭлемент.ПравоеЗначение = Неопределено;
    КонецЕсли;
КонецЕсли;

Метод 3. Рекурсивный поиск в группах отбора

Проанализируем ситуацию, когда отбор находится не в корне, а внутри группы (например, в группе «ИЛИ»). Обычный цикл не увидит такие элементы. В этом случае нам потребуется рекурсивная процедура. Давайте создадим универсальный механизм для отключения отборов по имени поля.


Процедура ОтключитьОтборРекурсивно(ГруппаЭлементов, ИмяПоля)
    ПолеПоиска = Новый ПолеКомпоновкиДанных(ИмяПоля);
    
    Для Каждого Элемент Из ГруппаЭлементов.Элементы Цикл
        Если ТипЗнч(Элемент) = Тип("ГруппаЭлементовОтбораКомпоновкиДанных") Тогда
            // Заходим внутрь группы
            ОтключитьОтборРекурсивно(Элемент, ИмяПоля);
        ИначеЕсли ТипЗнч(Элемент) = Тип("ЭлементОтбораКомпоновкиДанных") Тогда
            Если Элемент.ЛевоеЗначение = ПолеПоиска Тогда
                // Работаем с пользовательской настройкой
                ID = Элемент.ИдентификаторПользовательскойНастройки;
                ПользовательскийЭлемент = КомпоновщикНастроек.ПользовательскиеНастройки.Элементы.Найти(ID);
                Если ПользовательскийЭлемент <> Неопределено Тогда
                    ПользовательскийЭлемент.Использование = Ложь;
                КонецЕсли;
                // Также отключаем в основных настройках
                Элемент.Использование = Ложь;
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

// Вызов процедуры для корня отбора
ОтключитьОтборРекурсивно(КомпоновщикНастроек.Настройки.Отбор, "Организация");

Обновление отображения на форме

Выясним еще одну важную причину, по которой код может «не срабатывать». Если вы меняете настройки программно (например, в обработчике нажатия кнопки), форма может не узнать о том, что данные внутри компоновщика изменились. Чтобы интерфейс обновился и пользователь увидел снятые флажки или пустые поля, в конце процедуры обязательно выполните команду обновления формы.

Для управляемых форм это делается следующим образом:

ЭтаФорма.ОбновитьОтображениеДанных();

Различие между удалением и отключением

Проанализируем, что лучше: удалять элемент или снимать флаг использования?

Подведем итог: Чтобы программное управление отборами работало стабильно, всегда проверяйте наличие ИдентификаторПользовательскойНастройки. Именно через этот ID происходит связь между внутренними механизмами СКД и тем, что видит пользователь на своем экране. Работайте напрямую с коллекцией ПользовательскиеНастройки.Элементы, и тогда ваши изменения будут мгновенно отражаться в интерфейсе отчета.

← На главную