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

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

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

Исходная проблема: почему выбирается только один элемент при отборе по нескольким ссылкам?

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

Предположим, у нас есть задача показать в поле выбора счета учета только счета 10.08 и 10.09. Изначальная попытка могла выглядеть следующим образом:


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

НовыеПараметры = Новый ФиксированныйМассив(НовыйМассив); 
Элементы.СчетУчета.ПараметрыВыбора = НовыеПараметры;

При таком подходе мы фактически создаем массив из нескольких объектов ПараметрВыбора, каждый из которых имеет одно и то же имя отбора: "Отбор.Ссылка". Система 1С, при обработке массива параметров с одинаковыми именами, обычно применяет только последний указанный параметр. Именно поэтому в списке выбора оставался лишь один счет, а не два, как ожидалось. Мы пытались передать несколько инструкций "отбери по ссылке X", "отбери по ссылке Y", вместо одной инструкции "отбери по ссылкам X ИЛИ Y".

Решение 1: Отбор по нескольким значениям для одного реквизита

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

Давайте посмотрим на исправленный и правильный подход:

  1. Создадим обычный Массив, в который поместим ссылки на все необходимые счета.
  2. Преобразуем этот Массив в ФиксированныйМассив. Это ключевой момент, так как именно ФиксированныйМассив используется как значение для параметра отбора по нескольким значениям.
  3. Создадим один объект ПараметрВыбора, указав в качестве его имени "Отбор.Ссылка", а в качестве значения — ранее созданный ФиксированныйМассив со ссылками.
  4. Поместим этот единственный ПараметрВыбора в другой Массив (если требуется, но можно и сразу в ФиксированныйМассив), который затем преобразуем в ФиксированныйМассив и присвоим свойству ПараметрыВыбора элемента формы.

Пример кода, демонстрирующий этот подход:


// Шаг 1: Создаем обычный массив для хранения ссылок на счета
МассивСсылокСчетов = Новый Массив; 

// Шаг 2: Добавляем ссылки на нужные счета.
// Здесь мы используем метод НайтиПоКоду() для примера, 
// но далее мы подробно обсудим более предпочтительные способы получения ссылок.
МассивСсылокСчетов.Добавить(ПланыСчетов.Хозрасчетный.НайтиПоКоду("10.08")); 
МассивСсылокСчетов.Добавить(ПланыСчетов.Хозрасчетный.НайтиПоКоду("10.09")); 

// Шаг 3: Преобразуем массив ссылок в ФиксированныйМассив.
// Это и есть то "множественное значение" для одного параметра отбора.
ЗначенияОтбораПоСсылкам = Новый ФиксированныйМассив(МассивСсылокСчетов); 

// Шаг 4: Создаем один объект ПараметрВыбора с именем "Отбор.Ссылка"
// и передаем ему ФиксированныйМассив со значениями.
ПараметрОтбораПоСсылкам = Новый ПараметрВыбора("Отбор.Ссылка", ЗначенияОтбораПоСсылкам); 

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

// Шаг 6: Присваиваем ФиксированныйМассив параметров свойству ПараметрыВыбора элемента формы.
Элементы.СчетУчета.ПараметрыВыбора = Новый ФиксированныйМассив(МассивПараметровВыбора); 

// Показываем форму для применения изменений
Показать();

После применения этого кода, при открытии формы выбора плана счетов, пользователь увидит в списке только счета с кодами 10.08 и 10.09. Этот подход корректно интерпретируется системой как отбор "по одной из перечисленных ссылок".

Решение 2: Одновременное применение нескольких условий отбора по разным реквизитам

Если задача состоит в том, чтобы применить несколько разных условий отбора, каждое из которых относится к своему реквизиту объекта (например, отбор по месяцу регистрации И по признаку "Проведен"), то мы будем использовать другой подход. В этом случае мы создаем несколько объектов ПараметрВыбора, каждый с уникальным именем отбора (например, "Отбор.ПериодРегистрации", "Отбор.Проведен"), и объединяем их в один ФиксированныйМассив, который затем присваиваем свойству ПараметрыВыбора.

Эти параметры будут объединены по логическому "И", то есть в списке выбора будут показаны только те элементы, которые удовлетворяют *всем* заданным условиям одновременно.

Рассмотрим пример ограничения выбора документов "Табель" только проведенными документами за текущий месяц:


МассивПараметров = Новый Массив; 

// --- Добавляем первый параметр: отбор по месяцу регистрации -------------------------------
// Создаем массив значений для отбора по месяцу (если нужно несколько месяцев, то сюда)
МассивЗначенийПериодаРегистрации = Новый Массив; 
МассивЗначенийПериодаРегистрации.Добавить(МЕСЯЦ(ТекущаяДата())); // Отбираем по текущему месяцу

// Преобразуем в ФиксированныйМассив, если нужно несколько значений,
// или можно просто передать одно значение, если отбор по одному месяцу
ЗначенияПериодаРегистрации = Новый ФиксированныйМассив(МассивЗначенийПериодаРегистрации); 

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

// --- Добавляем второй параметр: отбор по признаку "Проведен" ------------------------------
// Создаем массив значений для отбора по признаку "Проведен"
МассивЗначенийПроведен = Новый Массив; 
МассивЗначенийПроведен.Добавить(Истина); // Нам нужны только проведенные документы

// Преобразуем в ФиксированныйМассив
ЗначенияПроведен = Новый ФиксированныйМассив(МассивЗначенийПроведен); 

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

// --- Применяем все параметры -----------------------------------------------------------
// Объединяем все ПараметрыВыбора в один ФиксированныйМассив
НовыеПараметры = Новый ФиксированныйМассив(МассивПараметров); 

// Присваиваем его свойству ПараметрыВыбора элемента формы
Элементы.ТаблицаНаФормеТабель.ПараметрыВыбора = НовыеПараметры; 

// Показываем форму
Показать();

В этом примере мы создали два разных объекта ПараметрВыбора: один для отбора по ПериодРегистрации, другой для Проведен. Каждый из них добавляется в общий МассивПараметров, который затем преобразуется в ФиксированныйМассив и передается элементу формы. Это обеспечивает корректное применение обоих условий одновременно.

Важный аспект: Выбор метода получения ссылки (НайтиПоКоду vs. ПредопределенноеЗначение)

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

Метод НайтиПоКоду() (или НайтиПоНаименованию())

Этот метод используется для поиска элемента по его коду или наименованию. Например: ПланыСчетов.Хозрасчетный.НайтиПоКоду("10.08").

  1. Преимущества:
    • Простота использования: Легко написать и понять, особенно для разработчиков, знакомых с другими системами, где поиск по строковому идентификатору является нормой.
    • Гибкость для внешних решений: Часто используется во внешних отчетах и обработках, где нельзя изменять конфигурацию. Для таких случаев это может быть единственным или наиболее простым способом привязки к конкретным элементам.
    • Работа с непостоянными данными: Позволяет получать ссылки на элементы, которые не являются предопределенными и могут быть созданы пользователем.
  2. Недостатки и риски:
    • Зависимость от пользовательских изменений: Коды и наименования элементов могут быть изменены пользователями. Если, например, бухгалтер решит поменять код счета 10.08 на 10.008, ваш код перестанет работать.
    • Риск при обновлениях: Разработчики типовых конфигураций иногда меняют коды или наименования предопределенных элементов при обновлениях, что также может нарушить работу вашего решения.
    • Неоднозначность: В некоторых случаях коды или наименования могут быть не уникальными, что приведет к неверному выбору элемента.

Когда стоит использовать: Если мы абсолютно уверены, что код или наименование элемента не изменится (как, например, в случае с некоторыми исторически стабильными кодами счетов, которые не менялись десятилетиями), или если это внешняя обработка/отчет, которая не может изменять конфигурацию, и риски изменения кода приемлемы.

Метод ПредопределенноеЗначение()

Этот метод предназначен для получения ссылки на предопределенный элемент метаданных. Он использует внутреннее, уникальное и стабильное имя предопределенного значения. Например: ПредопределенноеЗначение("ПланСчетов.Хозрасчетный.Материалы").

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

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

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

Дискуссия о "руках отрывать" и компромиссах

На форуме возникла острая дискуссия о допустимости использования НайтиПоКоду(). Мы выяснили, что в идеальном мире для предопределенных элементов всегда следует использовать ПредопределенноеЗначение().

Однако на практике существуют компромиссы:

  1. Внешние отчеты и обработки: В случаях, когда нельзя изменять типовую конфигурацию (например, по требованиям заказчика или из-за сложностей с обновлениями), использование НайтиПоКоду() во внешних решениях может быть единственным разумным выходом. Добавление констант или регистров сведений в типовую конфигурацию для хранения ссылок, ради внешней обработки, может создать больше проблем при обновлении, чем простое использование НайтиПоКоду() для стабильных кодов.
  2. Стабильность кодов: Некоторые коды (например, коды основных счетов бухгалтерского учета, как 10.08) действительно крайне редко меняются. В таких специфических случаях риск использования НайтиПоКоду() может быть оценен как низкий.
  3. Автоматизация обновлений: Если конфигурация не дорабатывается (не "включена возможность изменения"), ее обновление происходит автоматически. Добавление новых объектов (регистров, констант) для хранения ссылок требует включения возможности изменения, что усложняет процесс обновления для конечного пользователя, иногда доверяющего обновление системному администратору или бухгалтеру.

В то же время, важно помнить о риске: даже если коды стабильны годами, всегда есть вероятность, что пользователь или разработчик изменит их. Использование констант или регистров сведений для хранения таких ссылок в самой конфигурации (если есть возможность ее доработать) является наиболее надежным методом, так как пользователь будет изменять значение константы/регистра, а не код элемента, на который ссылается программа.

Дополнительные методы управления выбором

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

СвязиПараметровВыбора

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

ОбработкаПолученияДанныхВыбора

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

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

  1. Установить СтандартнаяОбработка = Ложь, чтобы отменить стандартный механизм формирования списка.
  2. Заполнить переменную ДанныеВыбора СпискомЗначений или Массивом, содержащим только те элементы, которые должны быть доступны для выбора.

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


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

    // Создаем новый СписокЗначений для вывода
    СписокДоступныхТоваров = Новый СписокЗначений;

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

    // Передаем сформированный список в ДанныеВыбора
    ДанныеВыбора = СписокДоступныхТоваров;
КонецПроцедуры

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

Диагностика проблем с отбором

Если программно установленные параметры выбора не работают или формируют неожиданный список, мы рекомендуем выполнить следующие шаги для диагностики:

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

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

← На главную