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

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

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

Рассмотрим комплексные подходы, которые позволяют нам эффективно управлять доступностью элементов справочника для выбора, гарантируя, что пользователь увидит только разрешенные значения.

1. Программное ограничение списка выбора через "ОбработкаПолученияДанныхВыбора"

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

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

Преимущества этого метода:

  1. Глобальный контроль: Логика отбора применяется ко всем формам выбора данного справочника, независимо от того, как они были открыты (стандартно, программно, через выпадающий список) — есть конструктор отборов для форм выбора 1С без программирования.
  2. Исключение предопределенных элементов: Мы можем легко исключить определенные предопределенные элементы, просто не добавляя их в наш список ДанныеВыбора.
  3. Гибкость: Отбор может быть динамическим и зависеть от любых условий, доступных в контексте выполнения.

Разберем подробнее на примере, как реализовать эту процедуру. Предположим, у нас есть справочник МоиЭлементы, и мы хотим исключить из выбора предопределенный элемент с наименованием "ЭлементДляАвтоВыбора", а также любой элемент, помеченный как "НеАктивный".


// В модуле менеджера справочника "МоиЭлементы"

Процедура ОбработкаПолученияДанныхВыбора(ДанныеВыбора, СтандартнаяОбработка) Экспорт
    СтандартнаяОбработка = Ложь; // Отменяем стандартную обработку

    // Создаем новый список значений для разрешенных элементов
    РазрешенныеЭлементы = Новый СписокЗначений;

    // Выполняем запрос для получения всех элементов справочника
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |    МоиЭлементы.Ссылка КАК Ссылка,
        |    МоиЭлементы.Наименование КАК Наименование,
        |    МоиЭлементы.Предопределенный КАК Предопределенный,
        |    МоиЭлементы.ПометкаУдаления КАК ПометкаУдаления
        |ИЗ
        |    Справочник.МоиЭлементы КАК МоиЭлементы
        |ГДЕ
        |    НЕ МоиЭлементы.ПометкаУдаления"; // Исключаем удаленные элементы сразу

    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();

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

        // Если у нас есть реквизит "НеАктивный", мы также можем его проверить
        // Предположим, у нас есть реквизит "НеАктивный" типа Булево
        // Если Выборка.НеАктивный Тогда
        //     Продолжить; // Пропускаем неактивные элементы
        // КонецЕсли;

        // Добавляем разрешенный элемент в список
        РазрешенныеЭлементы.Добавить(Выборка.Ссылка, Выборка.Наименование);
    КонецЦикла;

    // Передаем сформированный список в ДанныеВыбора
    ДанныеВыбора = РазрешенныеЭлементы;
КонецПроцедуры

В этом примере мы создаем запрос, который выбирает все непомеченные на удаление элементы справочника. Затем в цикле мы проверяем каждый элемент: если он является предопределенным с определенным наименованием (или соответствует другим условиям, которые мы хотим исключить), мы его пропускаем. Все остальные элементы добавляются в список РазрешенныеЭлементы, который затем присваивается параметру ДанныеВыбора.

2. Отключение истории выбора

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

Чтобы полностью исключить ранее выбранные, но ныне запрещенные элементы из выпадающего списка, нам необходимо отключить свойство ИсторияВыбораПриВводе. Это свойство может быть установлено на нескольких уровнях:

  1. Для прикладного объекта (справочника): Если мы хотим, чтобы история выбора была отключена, добавление реквизитов и элементов формы для управления выбором может быть сделано на уровне метаданных.
  2. Для реквизита объекта конфигурации: Если ограничение касается конкретного реквизита (например, реквизита табличной части документа), мы можем изменить свойство ИсторияВыбораПриВводе для этого реквизита.
  3. Для элемента формы: Это наиболее гибкий способ. Мы можем установить это свойство для конкретного элемента формы, отображающего данный реквизит. Это позволяет нам управлять историей выборов индивидуально для каждого поля.

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

Пример настройки для элемента формы:

Допустим, у нас есть элемент формы с именем Элементы.МойРеквизит, который является полем ввода справочника. Мы можем изменить его свойство в палитре свойств или программно:


// В обработчике ПриСозданииНаСервере или ПередОткрытием формы
// (или в другом подходящем месте, где доступен элемент формы)

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // Отключаем историю выбора для элемента формы
    Элементы.МойРеквизит.ИсторияВыбораПриВводе = ВариантИспользованияИсторииВыбора.НеИспользовать;
КонецПроцедуры

Таким образом, мы исключаем появление "старых" недопустимых значений в выпадающем списке, предоставляя пользователю чистый и актуальный список разрешенных элементов.

3. Использование "ПараметровВыбора" для динамических отборов

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

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

Пример использования ПараметровВыбора:

Предположим, мы хотим, чтобы в поле выбора справочника Номенклатура пользователь мог выбирать только товары, но не услуги.


// В обработчике ПриСозданииНаСервере формы

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

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

4. Управление списком выбора напрямую в событии "НачалоВыбора"

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

Для перехвата стандартной обработки мы устанавливаем параметр СтандартнаяОбработка в Ложь. Это позволяет реализовать сценарии программного изменения форм и заполнить свойство СписокВыбора.

Пример заполнения СписокВыбора:

Предположим, мы хотим показать только несколько предопределенных элементов, которые пользователь может выбрать, и больше ничего.


// В обработчике события НачалоВыбора для элемента формы МойРеквизит
&НаКлиенте
Процедура МойРеквизитНачалоВыбора(Элемент, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь; // Отменяем стандартное открытие формы выбора

    // Создаем новый СписокЗначений для элемента формы
    Элемент.СписокВыбора = Новый СписокЗначений;

    // Добавляем только разрешенные элементы
    Элемент.СписокВыбора.Добавить(Справочники.МоиЭлементы.ПредопределенныйЭлемент1, "Разрешенный элемент 1");
    Элемент.СписокВыбора.Добавить(Справочники.МоиЭлементы.ПредопределенныйЭлемент2, "Разрешенный элемент 2");
    // и так далее
КонецПроцедуры

Или, если нам нужно открыть собственную форму выбора:


// В обработчике события НачалоВыбора для элемента формы МойРеквизит
&НаКлиенте
Процедура МойРеквизитНачалоВыбора(Элемент, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь; // Отменяем стандартное открытие формы выбора

    // Создаем параметры для открытия формы выбора
    ПараметрыОткрытия = Новый Структура;
    ПараметрыОткрытия.Вставить("Заголовок", "Выберите нужный элемент");
    // Можем передать отборы или другие параметры в открываемую форму
    // ПараметрыОткрытия.Вставить("Отбор", ...); 

    // Открываем собственную форму выбора справочника с нашими параметрами
    // Например, если у нас есть своя форма выбора "ФормаВыбораСпециальная"
    ОткрытьФорму("Справочник.МоиЭлементы.ФормаВыбораСпециальная", ПараметрыОткрытия, Элемент);
КонецПроцедуры

Этот метод дает нам максимальную гибкость для формирования списка выбора, но требует больше программного кода и привязан к конкретному элементу формы. При этом, как и ПараметрыВыбора, он не влияет на выпадающий список истории выбора, который нужно отключать отдельно.

5. Дополнительная проверка при изменении

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

В этом обработчике мы проверяем выбранное или введенное значение. Для подготовки таких проверок важен анализ структуры метаданных, на основе которого мы очищаем поле ввода при ошибке.

Пример проверки в ПриИзменении:


// В обработчике события ПриИзменении для элемента формы МойРеквизит
&НаКлиенте
Процедура МойРеквизитПриИзменении(Элемент)
    // Получаем текущее значение реквизита
    ТекущееЗначение = Объект.МойРеквизит;

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

        // Если у элемента есть реквизит "НеАктивный", который делает его запрещенным
        Запрос = Новый Запрос;
        Запрос.Текст = 
            "ВЫБРАТЬ
            |    МоиЭлементы.НеАктивный
            |ИЗ
            |    Справочник.МоиЭлементы КАК МоиЭлементы
            |ГДЕ
            |    МоиЭлементы.Ссылка = &Ссылка";
        Запрос.УстановитьПараметр("Ссылка", ТекущееЗначение);
        Результат = Запрос.Выполнить().Выбрать();

        Если Результат.Следующий() Тогда
            Если Результат.НеАктивный Тогда
                ПоказатьПредупреждение(,"Выбор неактивного элемента запрещен.");
                Объект.МойРеквизит = Неопределено;
            КонецЕсли;
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

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

Краткий итог и рекомендации

Чтобы гарантированно не показывать определенный предопределенный элемент ни в форме выбора, ни в выпадающем списке, и полностью исключить его из пользовательского интерфейса выбора, мы рекомендуем использовать комбинацию следующих подходов:

  1. Реализовать логику исключения нежелательных элементов (включая предопределенные) в процедуре ОбработкаПолученияДанныхВыбора модуля менеджера справочника. Это обеспечит глобальный отбор для всех форм выбора.
  2. Отключить свойство ИсторияВыбораПриВводе для соответствующего реквизита или элемента формы. Это предотвратит появление ранее выбранных, но теперь запрещенных элементов в выпадающем списке истории выбора.
  3. В случае необходимости использовать ПараметрыВыбора для установки динамических отборов, зависящих от контекста формы, если ОбработкаПолученияДанныхВыбора недостаточно гибка для всех сценариев.
  4. Как последнюю меру безопасности, добавить проверку в событие ПриИзменении, чтобы перехватывать и аннулировать любые недопустимые значения, введенные вручную или из буфера обмена.

Применяя эти методы в комплексе, мы создаем надежную систему контроля выбора элементов справочника, которая полностью исключает возможность для пользователя выбрать нежелательные или служебные значения, обеспечивая при этом корректную работу автоматических механизмов, где эти элементы могут быть использованы.

← На главную