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