Как программно задать фильтр для выпадающих значений справочника в обычных формах 1С?

Программист 1С v8.3 (Обычные формы)
← На главную

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

Для программной установки фильтра в выпадающем списке справочника в обычных формах мы можем использовать несколько подходов. Наиболее гибким и часто применяемым является перехват стандартной обработки выбора и последующее открытие собственной формы выбора с предварительно настроенным отбором.

Перехват события НачалоВыбораИзСписка и настройка отбора

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

  1. Перехватываем стандартную обработку. Первым шагом является установка параметра СтандартнаяОбработка = Ложь;. Это критически важно, чтобы система не открыла стандартный, нефильтрованный список выбора после нашего вмешательства.
  2. Получаем форму выбора справочника. Для получения формы выбора справочника мы используем метод Справочники.<ИмяСправочника>.ПолучитьФормуВыбора(). Этот метод возвращает объект формы, с которым мы можем работать.
  3. Настраиваем отбор. Полученная форма выбора имеет свойство Отбор, которое представляет собой коллекцию элементов отбора. Каждый элемент отбора соответствует полю, по которому мы хотим фильтровать данные. Мы должны найти нужный элемент отбора, задать его вид сравнения, значение и активировать использование.

Давайте рассмотрим конкретный пример, где нам нужно отфильтровать список договоров контрагентов по определенной организации. Предположим, что у нас есть поле формы, в которое пользователь должен выбрать договор, и это поле связано с реквизитом типа "СправочникСсылка.ДоговорыКонтрагентов".


// Обработчик события НачалоВыбораИзСписка для элемента формы,
// который связан со справочником ДоговорыКонтрагентов
Процедура ЭлементФормыДоговорНачалоВыбораИзСписка(Элемент, СтандартнаяОбработка)

    СтандартнаяОбработка = Ложь; // Отменяем стандартную обработку выбора

    // Получаем форму выбора справочника "ДоговорыКонтрагентов"
    // Второй параметр Элемент (управляющий элемент формы) может быть полезен,
    // но в данном случае он не используется для настройки отбора напрямую.
    ФормаВыбора = Справочники.ДоговорыКонтрагентов.ПолучитьФормуВыбора(, Элемент);

    // *******************************************************************
    // 1. Настраиваем отбор по организации
    // *******************************************************************
    // Находим элемент отбора по полю "Организация".
    // Важно: имя поля отбора должно точно соответствовать имени реквизита
    // в справочнике или имени поля в динамическом списке формы выбора.
    ЭлементОтбораОрганизация = ФормаВыбора.Отбор.Организация;

    // Проверяем, что элемент отбора существует
    Если ЭлементОтбораОрганизация <> Неопределено Тогда
        // Устанавливаем вид сравнения "Равно"
        ЭлементОтбораОрганизация.ВидСравнения = ВидСравнения.Равно;
        // Задаем значение для отбора.
        // Предполагаем, что 'ОрганизацияДокумента' - это реквизит текущей формы документа,
        // содержащий нужную нам организацию.
        ЭлементОтбораОрганизация.Значение = ОрганизацияДокумента;
        // Активируем использование отбора
        ЭлементОтбораОрганизация.Использование = Истина;
    КонецЕсли;

    // *******************************************************************
    // 2. Решаем проблему с запросом выбора владельца (Контрагента)
    // *******************************************************************
    // Если справочник подчинен другому справочнику (например, ДоговорыКонтрагентов подчинены Контрагентам),
    // система по умолчанию может запрашивать выбор владельца.
    // Чтобы это предотвратить, мы должны явно установить отбор по владельцу.
    ЭлементОтбораВладелец = ФормаВыбора.Отбор.Владелец; // Владелец для ДоговоровКонтрагентов это Контрагент

    Если ЭлементОтбораВладелец <> Неопределено Тогда
        ЭлементОтбораВладелец.ВидСравнения = ВидСравнения.Равно;
        // Предполагаем, что 'КонтрагентДокумента' - это реквизит текущей формы документа,
        // содержащий нужного нам контрагента.
        ЭлементОтбораВладелец.Значение = КонтрагентДокумента;
        ЭлементОтбораВладелец.Использование = Истина;
    КонецЕсли;

    // *******************************************************************
    // 3. Отключаем доступность элементов пользовательского отбора (опционально)
    // *******************************************************************
    // Чтобы пользователь не мог изменить наш программный отбор,
    // мы можем сделать соответствующие элементы настройки отбора недоступными.
    // Имя "СправочникСписок" обычно является именем основного элемента формы типа "Таблица",
    // который отображает список справочника.
    // Имена полей отбора соответствуют именам реквизитов справочника.
    Если ФормаВыбора.ЭлементыФормы.Найти("СправочникСписок") <> Неопределено Тогда
        Если ФормаВыбора.ЭлементыФормы.СправочникСписок.НастройкаОтбора.Найти("Организация") <> Неопределено Тогда
            ФормаВыбора.ЭлементыФормы.СправочникСписок.НастройкаОтбора.Организация.Доступность = Ложь;
        КонецЕсли;
        Если ФормаВыбора.ЭлементыФормы.СправочникСписок.НастройкаОтбора.Найти("Владелец") <> Неопределено Тогда
            ФормаВыбора.ЭлементыФормы.СправочникСписок.НастройкаОтбора.Владелец.Доступность = Ложь;
        КонецЕсли;
    КонецЕсли;

    // *******************************************************************
    // 4. Открываем форму выбора
    // *******************************************************************
    ФормаВыбора.Открыть();

КонецПроцедуры

Разберем подробнее каждый шаг и ключевые объекты:

  1. СтандартнаяОбработка = Ложь;: Эта строка является "точкой перехвата". Без нее наша логика выполнится, но затем платформа все равно откроет стандартную форму выбора, что приведет к нежелательному поведению (открытию двух форм или игнорированию нашего отбора).
  2. Справочники.ДоговорыКонтрагентов.ПолучитьФормуВыбора(): Этот метод предоставляет нам экземпляр формы выбора справочника "ДоговорыКонтрагентов". Мы работаем именно с этой формой до ее открытия.
  3. ФормаВыбора.Отбор.<ИмяПоляОтбора>: Свойство Отбор объекта формы является коллекцией ЭлементыОтбора. К каждому элементу отбора мы обращаемся по имени соответствующего реквизита справочника (или поля динамического списка). Например, ФормаВыбора.Отбор.Организация обращается к элементу отбора по реквизиту "Организация" справочника. Если такого реквизита нет или он недоступен для отбора, обращение вернет Неопределено.
    • ЭлементОтбора.ВидСравнения: Мы указываем, как должно производиться сравнение. Чаще всего используется ВидСравнения.Равно для точного совпадения. Могут быть и другие виды сравнения, такие как ВидСравнения.Больше, ВидСравнения.Меньше, ВидСравнения.ВСписке и т.д.
    • ЭлементОтбора.Значение: Здесь мы указываем конкретное значение, по которому будет производиться отбор. Это должно быть значение того же типа, что и реквизит справочника, по которому мы фильтруем.
    • ЭлементОтбора.Использование = Истина;: Это активирует настроенный элемент отбора. Без этой строки отбор не будет применен, даже если вы задали все остальные параметры.

Решение проблемы "просит выбрать контрагента" (или другого владельца)

Часто, как это было указано в исходном сообщении, при работе с подчиненными справочниками (например, "ДоговорыКонтрагентов" подчинены "Контрагентам"), система по умолчанию может открыть диалог выбора владельца перед отображением списка подчиненных элементов. Это происходит, если отбор по владельцу не задан явно.

Чтобы избежать такого поведения, мы должны программно установить отбор не только по необходимым нам полям (например, организации), но и по полю Владелец. В нашем примере с договорами, Владелец — это Контрагент. Таким образом, мы должны передать системе, для какого именно контрагента следует показать договоры.

В приведенном выше коде этот момент учтен:


ЭлементОтбораВладелец = ФормаВыбора.Отбор.Владелец;
Если ЭлементОтбораВладелец <> Неопределено Тогда
    ЭлементОтбораВладелец.ВидСравнения = ВидСравнения.Равно;
    ЭлементОтбораВладелец.Значение = КонтрагентДокумента; // Задаем нужного контрагента
    ЭлементОтбораВладелец.Использование = Истина;
КонецЕсли;

Здесь КонтрагентДокумента должен быть ссылкой на элемент справочника "Контрагенты", который соответствует владельцу наших договоров. Если в форме выбора справочника отсутствует колонка для отображения владельца, то при открытии формы отключается возможность управления отбором пользователем, что позволяет просматривать список строго по указанному владельцу, без лишних запросов.

Скрытие пользовательского отбора

Если мы хотим, чтобы пользователь не мог изменить или отключить программно заданный отбор, мы можем установить свойство Доступность для соответствующих элементов настройки отбора в Ложь. Это повышает целостность данных и предотвращает ошибки пользователя.


Если ФормаВыбора.ЭлементыФормы.Найти("СправочникСписок") <> Неопределено Тогда
    Если ФормаВыбора.ЭлементыФормы.СправочникСписок.НастройкаОтбора.Найти("Организация") <> Неопределено Тогда
        ФормаВыбора.ЭлементыФормы.СправочникСписок.НастройкаОтбора.Организация.Доступность = Ложь;
    КонецЕсли;
    Если ФормаВыбора.ЭлементыФормы.СправочникСписок.НастройкаОтбора.Найти("Владелец") <> Неопределено Тогда
        ФормаВыбора.ЭлементыФормы.СправочникСписок.НастройкаОтбора.Владелец.Доступность = Ложь;
    КонецЕсли;
КонецЕсли;

Здесь СправочникСписок является стандартным именем элемента формы типа "Таблица", который отображает список справочника. А НастройкаОтбора - это коллекция элементов, позволяющих управлять пользовательскими отборами. Мы обращаемся к конкретным элементам отбора по имени реквизита (например, "Организация" или "Владелец") и устанавливаем их доступность.

Дополнительные подходы и нюансы

Помимо рассмотренного основного метода, существуют и другие способы реализации отбора, а также важные нюансы, которые необходимо учитывать при работе с обычными формами 1С.

  1. Динамические списки: Важно помнить, что отбор работает только с формами, у которых основным реквизитом является ДинамическийСписок. Это относится к большинству форм списка и форм выбора справочников, документов и других объектов в современных версиях 1С.
  2. ПараметрОтборПоВладельцу и ПараметрВыборПоВладельцу: Для работы с подчиненными справочниками существуют специальные свойства формы списка справочника, которые можно использовать при получении формы.
    • ПараметрОтборПоВладельцу: Используется для отображения списка по определенному владельцу.
    • ПараметрВыборПоВладельцу: Инициализирует форму выбора таким образом, чтобы выбор выполнялся только для элементов с указанным владельцем. Мы можем передать эти параметры при получении формы выбора:
      
      // Пример использования ПараметрВыборПоВладельцу
      СтруктураПараметров = Новый Структура("ПараметрВыборПоВладельцу", КонтрагентДокумента);
      ФормаВыбора = Справочники.ДоговорыКонтрагентов.ПолучитьФормуВыбора(СтруктураПараметров, Элемент);
      
      Этот подход зачастую более лаконичен, чем ручное заполнение ФормаВыбора.Отбор.Владелец.
  3. СвязиПараметровВыбора: Это свойство элемента формы срабатывает при выборе значений реквизита формы и отвечает за формирование списка элементов в форме выбора по установленному отбору. Оно позволяет указать список реквизитов, которые будут поставлять значения для отбора при открытии формы выбора, быстром выборе и вводе по строке. Мы можем устанавливать и изменять его программно. Например, если у нас есть поле "Контрагент", и при его изменении нужно автоматически фильтровать "Договор", мы можем связать эти поля.
    
    // В процедуре ПриОткрытии или при создании элемента
    // Предполагаем, что ЭлементФормыДоговор - это элемент типа ПолеВвода для выбора договора
    // А ЭлементФормыКонтрагент - это элемент типа ПолеВвода для выбора контрагента
    ЭлементФормыДоговор.СвязиПараметровВыбора.Добавить("Владелец", "Контрагент", "Контрагент");
    // Первая строка - имя параметра отбора в справочнике ДоговорыКонтрагентов
    // Вторая строка - имя реквизита формы, который будет поставлять значение
    // Третья строка (опционально) - имя колонки в справочнике, по которой будет осуществляться поиск
    
    Этот метод более декларативный и может упростить код при наличии фиксированных связей между полями формы. Однако для сложной динамической логики, НачалоВыбораИзСписка остается более гибким.
  4. Передача параметров отбора через Структуру: При использовании метода ОткрытьФорму() для открытия формы выбора с отбором, параметры отбора можно передать как Структуру в качестве второго параметра метода. Это позволяет избежать прямого обращения к ФормаВыбора.Отбор после получения формы.
    
    // Пример передачи параметров отбора при открытии формы
    СтруктураОтбора = Новый Структура();
    СтруктураОтбора.Вставить("Организация", ОрганизацияДокумента);
    СтруктураОтбора.Вставить("Владелец", КонтрагентДокумента);
    
    // Если нужно передать отбор в форму списка (например, когда открываем форму списка справочника)
    // Можно использовать для этого метод ОткрытьФорму() глобального контекста
    // Имя формы выбора обычно имеет формат Справочник.ИмяСправочника.ФормаВыбора
    ОткрытьФорму("Справочник.ДоговорыКонтрагентов.ФормаВыбора", СтруктураОтбора, Элемент);
    СтандартнаяОбработка = Ложь;
    
    Такой подход удобен, если отбор достаточно простой и не требует сложной логики по видам сравнения.
  5. Проверка имени отбора: Если отбор не работает, всегда следует проверять правильность имени элемента отбора. Это можно сделать, открыв форму списка справочника вручную, нажав кнопку "Отбор и сортировка", или же поставив точку останова в процедуре ПриОткрытии формы списка и проверив имена доступных элементов отбора с помощью отладчика (например, через ФормаВыбора.Отбор).
  6. Метод ВыбратьИзСписка(): Если требуется выбор из небольшого, жестко заданного списка значений (например, для перечислений или нескольких фиксированных элементов справочника), можно использовать метод ВыбратьИзСписка(). Он открывает выпадающий список из переданных значений, что значительно проще, но менее гибко для большого динамического списка справочника.
    
    // Пример использования ВыбратьИзСписка
    СписокЗначений = Новый СписокЗначений();
    СписокЗначений.Добавить(Ссылка1, "Значение 1");
    СписокЗначений.Добавить(Ссылка2, "Значение 2");
    ВыбранноеЗначение = СписокЗначений.ВыбратьИзСписка();
    Если ВыбранноеЗначение <> Неопределено Тогда
        Элемент.Значение = ВыбранноеЗначение;
    КонецЕсли;
    

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

← На главную