Как изменить логику стандартного поиска в динамическом списке 1С и настроить отбор по иерархии

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

При работе с управляемыми формами в 1С:Предприятие 8.3 разработчики часто сталкиваются с ограничением стандартного механизма поиска. Типичная ситуация: в динамическом списке есть поле со ссылкой на иерархический справочник. Пользователь открывает расширенный поиск, выбирает группу, и ожидает увидеть все элементы, входящие в эту группу. Однако система по умолчанию использует вид сравнения «Равно», из-за чего список оказывается пустым или содержит только саму группу, если ее отображение разрешено.

В этой статье мы подробно разберем, почему стандартное событие ОбработкаВыбора не помогает в данной ситуации, и как правильно «вклиниться» в логику работы динамического списка для реализации поиска по иерархии.

Почему стандартная «ОбработкаВыбора» не работает для поиска

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

Именно поэтому процедура ОбработкаВыбора на основной форме не срабатывает — результат выбора возвращается в системный механизм поиска, который затем программно накладывает фильтр на ваш ДинамическийСписок. Нам необходимо найти способ перехватить этот фильтр уже после того, как поиск его сформировал, но до того, как запрос будет исполнен базой данных.

Решение 1: Использование события «ПриУстановкеПараметровЗапросаНаСервере»

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

Рассмотрим алгоритм действий:

  1. В свойствах динамического списка на форме создадим обработчик события ПриУстановкеПараметровЗапросаНаСервере.
  2. Внутри обработчика проанализируем текущие настройки компоновки данных.
  3. Найдем нужный нам элемент отбора и заменим его вид сравнения.

Посмотрим на пример кода, который реализует эту логику:


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

Важный нюанс: для того чтобы этот код работал, у поля в конфигураторе должно быть установлено свойство «Выбор групп и элементов» в значение «Группы и элементы». В противном случае платформа просто не позволит пользователю выбрать группу в диалоге поиска.

Решение 2: Программная модификация компоновщика настроек

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

Этот метод полезен, если вы хотите, чтобы пользователь видел изменение вида сравнения в интерфейсе отборов (если они выведены на форму).


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

Использование функции ОбщегоНазначения.ЗначениеЯвляетсяГруппой (или прямого запроса к БД) необходимо, так как на сервере нам нужно точно знать тип объекта (группа это или элемент).

Альтернативный подход: Собственный фильтр вместо стандартного поиска

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

Разберем по шагам создание такого фильтра:

  1. Добавьте на форму реквизит с типом ссылки на нужный справочник (например, ФильтрПоГруппе).
  2. Разместите его над списком и установите режим выбора «Группы и элементы».
  3. В событии ПриИзменении этого поля пропишите программную установку отбора в динамический список.

Пример реализации программного отбора:


&НаКлиенте
Процедура ФильтрПоГруппеПриИзменении(Элемент)
    УстановитьОтборСпискаНаСервере(ФильтрПоГруппе);
КонецПроцедуры

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

Подведем итоги

Мы проанализировали ситуацию, когда стандартный поиск 1С работает не так, как ожидается при выборе иерархических данных. Главный вывод: не пытайтесь ловить выбор в форме через ОбработкаВыбора, если открыт системный поиск — это не сработает из-за особенностей владения формами.

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

← На главную