Как программно установить, изменить или очистить отбор в отчете СКД при изменении реквизита на форме?

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

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

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

Причина дублирования отборов и общая логика правильного решения

Проанализируем типовую ошибку разработчиков: при наступлении события ПриИзменении на клиенте вызывается серверная процедура, в которой безусловно вызывается добавление элемента отбора:


// Ошибочный подход — приводит к накоплению дублирующих условий
НовыйЭлементОтбора = Отчет.КомпоновщикНастроек.Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
НовыйЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Задание");
НовыйЭлементОтбора.ПравоеЗначение = Отчет.Задание;
НовыйЭлементОтбора.Использование = Истина;

Если пользователь последовательно выберет сначала «Документ №1», а затем «Документ №2», в коллекции Отбор.Элементы сформируются два независимых отбора. В результате СКД попытается сформировать запрос, где одновременно Задание = Документ №1 И Задание = Документ №2, что сделает выборку пустой.

Правильный алгоритм работы строится следующим образом:

  1. Определяем требуемое поле отбора через объект ПолеКомпоновкиДанных.
  2. Выполняем обход коллекции существующих элементов отбора и проверяем свойство ЛевоеЗначение.
  3. Если нужный отбор найден — перезаписываем его свойства (значение, вид сравнения, флаг использования).
  4. Если отбор отсутствует — добавляем новый элемент в коллекцию.
  5. Если переданное значение пустое — отключаем признак Использование или удаляем элемент.

Способ 1. Программный поиск и обновление элемента отбора в настройках СКД

Рассмотрим базовый серверный метод, который проверяет наличие отбора по полю перед его модификацией или созданием. Данный код размещается в модуле формы отчета:


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

Способ 2. Особенность управляемых форм: работа с пользовательскими настройками

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

Если отбор выведен в быстрый доступ, прямое изменение Отчет.КомпоновщикНастроек.Настройки.Отбор не обновит элемент на экране, а при формировании отчета пользовательские настройки перекроют базовые. Разберем универсальный код, обновляющий и пользовательские настройки:


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

Разбор частых ошибок при установке отборов

Выясним причины ошибок, которые часто возникают при самостоятельной реализации алгоритма:

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

Способ 3. Использование готовых функций БСП

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


// Пример установки отбора через механизм БСП
КомпоновкаДанныхКлиентСервер.УстановитьЭлементОтбора(
    Отчет.КомпоновщикНастроек.Настройки.Отбор,
    "Задание",
    Отчет.Задание,
    ВидСравненияКомпоновкиДанных.Равно,
    ,
    ЗначениеЗаполнено(Отчет.Задание)
);

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

Альтернативное решение: использование параметров СКД

Если требуется жесткая фильтрация на уровне запроса без возможности случайного отключения пользователем, эффективнее перенести фильтр в параметры СКД. Для этого в тексте запроса схемы компоновки прописывается условие {ГДЕ ДокументТаблицы.Задание = &Задание}, а в коде формы значение передается одной строкой:


&НаСервере
Процедура УстановитьПараметрОтчета(ИмяПараметра, ЗначениеПараметра)
    Параметр = Отчет.КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти(ИмяПараметра);
    Если Параметр <> Неопределено Тогда
        Параметр.Значение = ЗначениеПараметра;
        Параметр.Использование = ЗначениеЗаполнено(ЗначениеПараметра);
    КонецЕсли;
КонецПроцедуры

Такой подход полностью исключает проблему дублирования элементов отбора и делает код формы максимально компактным и устойчивым к изменениям настроек отчета.

← На главную