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