Как программно отключить или изменить отбор в динамическом списке, если свойство Использование не срабатывает

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

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

Анализируем проблему: почему стандартный подход не работает

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

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

Если у элемента отбора в конфигураторе установлен флаг «Включать в пользовательские настройки», система присваивает ему уникальный ИдентификаторПользовательскойНастройки. С этого момента платформа начинает игнорировать состояние свойства Использование в основной коллекции настроек и берет значение исключительно из коллекции пользовательских настроек. Именно поэтому код ЭлементОтбора.Использование = Ложь в основном дереве настроек не дает никакого эффекта — система просто не смотрит в это поле.

Разберем правильный алгоритм управления отбором

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


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

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

Почему поиск по «Представлению» — это опасно?

В приведенном выше коде используется условие ЭлементОтбора.Представление = "НачалоПериода". Это крайне ненадежный подход. Выясним причину: представление — это просто строковая метка для пользователя. Если вы или другой разработчик измените имя в конфигураторе (например, напишете «Дата начала» вместо «НачалоПериода»), код молча перестанет работать. Более того, при использовании в многоязычных интерфейсах представление может измениться в зависимости от языка сеанса.

Рассмотрим более надежный способ — поиск по левому значению (полю компоновки). Поле компоновки данных — это объектный путь к данным, который не зависит от визуального отображения.


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

Использование инструментов БСП для упрощения кода

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

Пример использования функций БСП:


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

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

Дополнительные нюансы работы с периодами

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

Также важно помнить о безопасности. Как мы выяснили ранее, пользователь имеет возможность самостоятельно удалять элементы отбора через окно «Настройка списка». Если ваш код полагается на наличие определенного идентификатора, всегда проверяйте результат поиска на Неопределено, прежде чем обращаться к свойствам найденного элемента. Это предотвратит аварийное завершение работы программы у пользователя.

Подведем итог: для корректного программного отключения отбора в динамическом списке всегда проверяйте наличие ИдентификатораПользовательскойНастройки. Если он заполнен — работайте с коллекцией ПользовательскиеНастройки. Старайтесь избегать привязки к строковым представлениям и используйте возможности БСП для минимизации кода.

← На главную