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