При разработке на платформе 1С:Предприятие 8.3 одной из самых частых задач, с которыми мы сталкиваемся, является необходимость фильтрации данных в динамических списках. Динамический список — это основной инструмент отображения списков справочников, документов и регистров в управляемом интерфейсе. Зачастую нам необходимо показать пользователю не весь массив данных, а лишь определенную выборку, зависящую от текущего контекста: роли пользователя, настроек программы или параметров открытия формы.
В этой статье мы подробно разберем, как грамотно и эффективно управлять отборами программно. Мы проанализируем структуру объекта ДинамическийСписок, рассмотрим работу с компоновщиком настроек и изучим несколько подходов к решению этой задачи: от "классического" метода прямой работы с коллекциями до использования процедур Библиотеки Стандартных Подсистем (БСП).
Представим типичную ситуацию: у нас есть форма списка документов "Заказы покупателей". Нам необходимо при открытии этой формы установить отбор так, чтобы менеджер видел только заказы, находящиеся в статусе "В работе". Или, например, мы открываем форму подбора номенклатуры и хотим сразу скрыть услуги, оставив только товары.
Прежде чем переходить к написанию кода, давайте вспомним, как устроен ДинамическийСписок. В управляемых формах это не просто таблица, а сложный объект, который использует механизмы Системы Компоновки Данных (СКД). У него есть свойство КомпоновщикНастроек, которое отвечает за все настройки отображения: отборы, сортировки, группировки и условное оформление.
Мы будем работать именно с этим свойством. Важно понимать, что настройки компоновки данных делятся на:
Рассмотрим несколько способов реализации нашей задачи, от базовых к более продвинутым.
Этот метод является наиболее универсальным и не требует наличия внедренной Библиотеки Стандартных Подсистем. Он работает в любой конфигурации на управляемых формах. Наша цель — добавить новый элемент в коллекцию Отбор компоновщика настроек списка.
Обычно этот код размещается в процедуре ПриСозданииНаСервере модуля формы. Разберем его по шагам.
Сначала нам нужно получить доступ к коллекции элементов отбора. В ДинамическомСписке она находится по пути Список.КомпоновщикНастроек.Настройки.Отбор.Элементы. Создадим новый элемент отбора и заполним его свойства.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Получаем доступ к настройкам списка
СписокЗаказов = Элементы.Список; // Или просто используем реквизит формы "Список", если он основной
// Очистим текущие отборы, если это необходимо по логике задачи
// Список.КомпоновщикНастроек.Настройки.Отбор.Элементы.Очистить();
// Добавляем новый элемент отбора
НовыйОтбор = Список.КомпоновщикНастроек.Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
// Указываем поле, по которому будем фильтровать.
// Важно: имя поля должно совпадать с именем поля в запросе динамического списка или реквизитом объекта.
НовыйОтбор.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Статус");
// Указываем вид сравнения. Чаще всего это "Равно", "ВСписке" или "Содержит".
НовыйОтбор.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
// Задаем значение, с которым сравниваем
НовыйОтбор.ПравоеЗначение = Перечисления.СтатусыЗаказов.ВРаботе;
// Включаем отбор
НовыйОтбор.Использование = Истина;
// Опционально: запрещаем пользователю менять этот отбор
НовыйОтбор.РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Недоступный;
КонецПроцедуры
Давайте проанализируем этот код. Мы создали объект типа ЭлементОтбораКомпоновкиДанных. Обратите внимание на использование конструктора Новый ПолеКомпоновкиДанных("ИмяПоля"). Это критически важный момент: нельзя просто передать строку, система ожидает именно объект типа ПолеКомпоновкиДанных.
Важное дополнение про пользовательские настройки:
Если вы изменяете настройки в КомпоновщикНастроек.Настройки, они применяются как "базовые". Однако, если у элемента списка (таблицы на форме) свойство ПутьКДанным указывает на динамический список, то в момент отображения платформа может наложить сверху ПользовательскиеНастройки (те, что пользователь настроил сам, нажав "Настроить список").
Иногда возникают ситуации, когда ваш программный отбор не срабатывает или конфликтует с пользовательским. В сложных случаях может потребоваться работа с коллекцией Список.КомпоновщикНастроек.ПользовательскиеНастройки. Но для задачи "жесткого" фильтра при открытии, описанный выше метод с коллекцией Настройки (Settings) является предпочтительным, так как он накладывает условие на уровне генерации запроса к базе данных.
Если ваша конфигурация построена на базе БСП (например, 1С:ERP, Управление Торговлей 11, Бухгалтерия 3.0, ЗУП 3.1), то нам доступен гораздо более элегантный и компактный способ. Разработчики 1С уже написали удобные обертки для рутинных операций.
Мы будем использовать модуль ОбщегоНазначенияКлиентСервер. Это позволяет сократить код до одной строчки и избавиться от необходимости помнить типы данных компоновки.
Посмотрим, как это выглядит на практике:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Устанавливаем отбор одной строкой
ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбора(
Список.КомпоновщикНастроек, // Объект компоновщика
"Статус", // Имя поля
Перечисления.СтатусыЗаказов.ВРаботе, // Значение отбора
ВидСравненияКомпоновкиДанных.Равно, // Вид сравнения
"Только активные заказы", // Представление (заголовок) отбора
Истина // Использование
);
КонецПроцедуры
Давайте разберем преимущества этого метода. Во-первых, читаемость кода значительно повышается. Во-вторых, функция внутри себя корректно обрабатывает создание полей компоновки данных и проверку на существование такого отбора (чтобы не дублировать его при повторном вызове кода).
Если вам нужно установить отбор по списку значений (например, показать заказы со статусами "В работе" ИЛИ "Ожидает отгрузки"), код изменится незначительно:
СписокСтатусов = Новый СписокЗначений;
СписокСтатусов.Добавить(Перечисления.СтатусыЗаказов.ВРаботе);
СписокСтатусов.Добавить(Перечисления.СтатусыЗаказов.ОжидаетОтгрузки);
ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбора(
Список.КомпоновщикНастроек,
"Статус",
СписокСтатусов,
ВидСравненияКомпоновкиДанных.ВСписке // Обратите внимание на вид сравнения
);
Иногда логика отбора настолько сложна, что простыми условиями "Равно" или "В Списке" не обойтись. Или же нам нужно не просто отфильтровать, а изменить логику выборки данных в самом запросе. В этом случае мы можем использовать параметры динамического списка.
Для этого в свойствах динамического списка в конфигураторе должен быть написан Произвольный запрос, содержащий параметры. Например:
ВЫБРАТЬ
Заказ.Ссылка,
Заказ.Дата,
Заказ.Контрагент
ИЗ
Документ.ЗаказПокупателя КАК Заказ
ГДЕ
Заказ.Ответственный = &ТекущийПользователь
Теперь, чтобы этот список заработал, нам нужно обязательно передать значение параметра &ТекущийПользователь. Сделаем это программно при создании формы:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Установка параметра динамического списка
Список.Параметры.УстановитьЗначениеПараметра("ТекущийПользователь", Пользователи.ТекущийПользователь());
КонецПроцедуры
Рассмотрим нюансы этого метода:
Бывают ситуации, когда нам нужно установить сложное условие. Например: (Статус = "Новый") ИЛИ (Менеджер = ТекущийПользователь). В этом случае простых элементов отбора недостаточно, нам нужно создавать группы.
Проанализируем, как создать группу "ИЛИ" программно:
&НаСервере
Процедура УстановитьСложныйОтбор()
КоллекцияЭлементов = Список.КомпоновщикНастроек.Настройки.Отбор.Элементы;
КоллекцияЭлементов.Очистить();
// Создаем группу с типом "ГруппаИли"
ГруппаИли = КоллекцияЭлементов.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
ГруппаИли.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИли;
// Добавляем элементы ВНУТРЬ этой группы
// Условие 1: Статус = Новый
Элемент1 = ГруппаИли.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
Элемент1.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Статус");
Элемент1.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
Элемент1.ПравоеЗначение = Перечисления.СтатусыЗаказов.Новый;
// Условие 2: Менеджер = Я
Элемент2 = ГруппаИли.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
Элемент2.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Менеджер");
Элемент2.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
Элемент2.ПравоеЗначение = Пользователи.ТекущийПользователь();
КонецПроцедуры
Этот код создает логическую структуру, которая будет интерпретирована платформой при построении SQL-запроса. Использование групп позволяет реализовывать гибкую логику фильтрации (например, отборы по шаблону списком), недоступную при простом перечислении отборов.
В процессе работы с динамическими списками мы часто можем столкнуться с неочевидным поведением. Давайте разберем основные "грабли":
Вы пытаетесь установить отбор по полю, которого нет в выборке запроса динамического списка. Убедитесь, что в конфигураторе в настройке списка (на закладке "Настройки" -> "Отбор") это поле доступно для выбора.
Проверьте, не перекрывает ли пользовательская настройка ваш программный код (например, если используются быстрые отборы через буфер). Попробуйте сбросить настройки списка в режиме 1С:Предприятие ("Еще" - "Установить стандартные настройки"). Также убедитесь, что вы устанавливаете свойство Использование = Истина.
ФиксированныеНастройки.
Некоторые программисты пытаются писать в Список.КомпоновщикНастроек.ФиксированныеНастройки. Это допустимо, но помните, что фиксированные настройки объединяются с обычными по логике "И". Если вы установите там жесткий отбор, пользователь никак не сможет его расширить.
Мы рассмотрели различные варианты программной установки отбора в динамическом списке. Для простых задач и типовых конфигураций рекомендуем использовать методы БСП (ОбщегоНазначенияКлиентСервер), так как это экономит время и снижает вероятность ошибок. Для более сложных, кастомных алгоритмов, лучше использовать прямую работу с коллекцией КомпоновщикНастроек.Настройки.Отбор или параметрами произвольного запроса.
Используйте полученные знания для создания удобных и отзывчивых интерфейсов, которые показывают пользователю именно ту информацию, которая ему нужна в данный момент.