При разработке форм в 1С часто возникает необходимость предоставить пользователю выбор из ограниченного списка значений, а не из полного набора данных. Например, требуется показать только определенные счета из плана счетов или только проведенные документы за конкретный период. Для решения этой задачи в 1С предусмотрен механизм ПараметрыВыбора. Однако его применение имеет свои особенности, особенно когда дело доходит до одновременного отбора по нескольким значениям одного реквизита или по нескольким разным реквизитам. Давайте разберемся, как правильно настроить такие параметры выбора, а также рассмотрим важные аспекты получения ссылок на объекты.
Часто разработчики сталкиваются с ситуацией, когда при попытке ограничить список выбора несколькими значениями одного и того же реквизита, например, ссылками на счета, в результате отображается только один, последний указанный элемент. Рассмотрим типовую ошибку, которая приводит к такому поведению.
Предположим, у нас есть задача показать в поле выбора счета учета только счета 10.08 и 10.09. Изначальная попытка могла выглядеть следующим образом:
НовыйМассив = Новый Массив;
// Получаем счета, например, из табличной части документа
Для Каждого ТекущаяСтрока Из ТЗ_СчетаУчета Цикл
// Создаем ПараметрВыбора для каждой ссылки
НовыйПараметр = Новый ПараметрВыбора("Отбор.Ссылка", ТекущаяСтрока.СчетУчета.Ссылка);
НовыйМассив.Добавить(НовыйПараметр);
КонецЦикла;
НовыеПараметры = Новый ФиксированныйМассив(НовыйМассив);
Элементы.СчетУчета.ПараметрыВыбора = НовыеПараметры;
При таком подходе мы фактически создаем массив из нескольких объектов ПараметрВыбора, каждый из которых имеет одно и то же имя отбора: "Отбор.Ссылка". Система 1С, при обработке массива параметров с одинаковыми именами, обычно применяет только последний указанный параметр. Именно поэтому в списке выбора оставался лишь один счет, а не два, как ожидалось. Мы пытались передать несколько инструкций "отбери по ссылке X", "отбери по ссылке Y", вместо одной инструкции "отбери по ссылкам X ИЛИ Y".
Для того чтобы ограничить список выбора элемента формы несколькими конкретными значениями одного и того же реквизита, необходимо передать в качестве значения для ПараметраВыбора не одиночную ссылку, а ФиксированныйМассив, содержащий все желаемые ссылки. Это позволяет системе понять, что отбор должен происходить по принципу "ИЛИ" для всех значений, указанных в массиве.
Давайте посмотрим на исправленный и правильный подход:
Массив, в который поместим ссылки на все необходимые счета.Массив в ФиксированныйМассив. Это ключевой момент, так как именно ФиксированныйМассив используется как значение для параметра отбора по нескольким значениям.ПараметрВыбора, указав в качестве его имени "Отбор.Ссылка", а в качестве значения — ранее созданный ФиксированныйМассив со ссылками.ПараметрВыбора в другой Массив (если требуется, но можно и сразу в ФиксированныйМассив), который затем преобразуем в ФиксированныйМассив и присвоим свойству ПараметрыВыбора элемента формы.Пример кода, демонстрирующий этот подход:
// Шаг 1: Создаем обычный массив для хранения ссылок на счета
МассивСсылокСчетов = Новый Массив;
// Шаг 2: Добавляем ссылки на нужные счета.
// Здесь мы используем метод НайтиПоКоду() для примера,
// но далее мы подробно обсудим более предпочтительные способы получения ссылок.
МассивСсылокСчетов.Добавить(ПланыСчетов.Хозрасчетный.НайтиПоКоду("10.08"));
МассивСсылокСчетов.Добавить(ПланыСчетов.Хозрасчетный.НайтиПоКоду("10.09"));
// Шаг 3: Преобразуем массив ссылок в ФиксированныйМассив.
// Это и есть то "множественное значение" для одного параметра отбора.
ЗначенияОтбораПоСсылкам = Новый ФиксированныйМассив(МассивСсылокСчетов);
// Шаг 4: Создаем один объект ПараметрВыбора с именем "Отбор.Ссылка"
// и передаем ему ФиксированныйМассив со значениями.
ПараметрОтбораПоСсылкам = Новый ПараметрВыбора("Отбор.Ссылка", ЗначенияОтбораПоСсылкам);
// Шаг 5: Помещаем этот ПараметрВыбора в новый массив (или сразу в ФиксированныйМассив),
// который будет содержать все параметры отбора для элемента формы.
МассивПараметровВыбора = Новый Массив;
МассивПараметровВыбора.Добавить(ПараметрОтбораПоСсылкам);
// Шаг 6: Присваиваем ФиксированныйМассив параметров свойству ПараметрыВыбора элемента формы.
Элементы.СчетУчета.ПараметрыВыбора = Новый ФиксированныйМассив(МассивПараметровВыбора);
// Показываем форму для применения изменений
Показать();
После применения этого кода, при открытии формы выбора плана счетов, пользователь увидит в списке только счета с кодами 10.08 и 10.09. Этот подход корректно интерпретируется системой как отбор "по одной из перечисленных ссылок".
Если задача состоит в том, чтобы применить несколько разных условий отбора, каждое из которых относится к своему реквизиту объекта (например, отбор по месяцу регистрации И по признаку "Проведен"), то мы будем использовать другой подход. В этом случае мы создаем несколько объектов ПараметрВыбора, каждый с уникальным именем отбора (например, "Отбор.ПериодРегистрации", "Отбор.Проведен"), и объединяем их в один ФиксированныйМассив, который затем присваиваем свойству ПараметрыВыбора.
Эти параметры будут объединены по логическому "И", то есть в списке выбора будут показаны только те элементы, которые удовлетворяют *всем* заданным условиям одновременно.
Рассмотрим пример ограничения выбора документов "Табель" только проведенными документами за текущий месяц:
МассивПараметров = Новый Массив;
// --- Добавляем первый параметр: отбор по месяцу регистрации -------------------------------
// Создаем массив значений для отбора по месяцу (если нужно несколько месяцев, то сюда)
МассивЗначенийПериодаРегистрации = Новый Массив;
МассивЗначенийПериодаРегистрации.Добавить(МЕСЯЦ(ТекущаяДата())); // Отбираем по текущему месяцу
// Преобразуем в ФиксированныйМассив, если нужно несколько значений,
// или можно просто передать одно значение, если отбор по одному месяцу
ЗначенияПериодаРегистрации = Новый ФиксированныйМассив(МассивЗначенийПериодаРегистрации);
// Создаем ПараметрВыбора для отбора по ПериодуРегистрации
ПараметрПериодРегистрации = Новый ПараметрВыбора("Отбор.ПериодРегистрации", ЗначенияПериодаРегистрации);
МассивПараметров.Добавить(ПараметрПериодРегистрации);
// --- Добавляем второй параметр: отбор по признаку "Проведен" ------------------------------
// Создаем массив значений для отбора по признаку "Проведен"
МассивЗначенийПроведен = Новый Массив;
МассивЗначенийПроведен.Добавить(Истина); // Нам нужны только проведенные документы
// Преобразуем в ФиксированныйМассив
ЗначенияПроведен = Новый ФиксированныйМассив(МассивЗначенийПроведен);
// Создаем ПараметрВыбора для отбора по признаку "Проведен"
ПараметрПроведен = Новый ПараметрВыбора("Отбор.Проведен", ЗначенияПроведен);
МассивПараметров.Добавить(ПараметрПроведен);
// --- Применяем все параметры -----------------------------------------------------------
// Объединяем все ПараметрыВыбора в один ФиксированныйМассив
НовыеПараметры = Новый ФиксированныйМассив(МассивПараметров);
// Присваиваем его свойству ПараметрыВыбора элемента формы
Элементы.ТаблицаНаФормеТабель.ПараметрыВыбора = НовыеПараметры;
// Показываем форму
Показать();
В этом примере мы создали два разных объекта ПараметрВыбора: один для отбора по ПериодРегистрации, другой для Проведен. Каждый из них добавляется в общий МассивПараметров, который затем преобразуется в ФиксированныйМассив и передается элементу формы. Это обеспечивает корректное применение обоих условий одновременно.
НайтиПоКоду vs. ПредопределенноеЗначение)В процессе работы с программным кодом 1С возникает вопрос о том, как наиболее надежно получить ссылку на элемент справочника, плана счетов или перечисления. Существуют два основных подхода: НайтиПоКоду() (или НайтиПоНаименованию()) и ПредопределенноеЗначение(). Выбор между ними зависит от контекста и требований к надежности решения.
НайтиПоКоду() (или НайтиПоНаименованию())Этот метод используется для поиска элемента по его коду или наименованию. Например: ПланыСчетов.Хозрасчетный.НайтиПоКоду("10.08").
Когда стоит использовать: Если мы абсолютно уверены, что код или наименование элемента не изменится (как, например, в случае с некоторыми исторически стабильными кодами счетов, которые не менялись десятилетиями), или если это внешняя обработка/отчет, которая не может изменять конфигурацию, и риски изменения кода приемлемы.
ПредопределенноеЗначение()Этот метод предназначен для получения ссылки на предопределенный элемент метаданных. Он использует внутреннее, уникальное и стабильное имя предопределенного значения. Например: ПредопределенноеЗначение("ПланСчетов.Хозрасчетный.Материалы").
Что такое предопределенный элемент? Предопределенный элемент в 1С — это обычный элемент справочника, плана счетов и т.д., который, помимо стандартных полей (код, наименование, ссылка), имеет уникальное имя предопределенного значения и соответствующий признак. Платформа при запуске системы загружает (кэширует) идентификаторы (ГУИДы) этих элементов во внутренние структуры, что обеспечивает быстрый доступ и стабильность ссылок.
Когда стоит использовать: Всегда, когда нам нужна ссылка на предопределенный элемент. Это предпочтительный метод для обеспечения надежности и устойчивости кода к изменениям данных пользователем или при обновлении конфигурации.
На форуме возникла острая дискуссия о допустимости использования НайтиПоКоду(). Мы выяснили, что в идеальном мире для предопределенных элементов всегда следует использовать ПредопределенноеЗначение().
Однако на практике существуют компромиссы:
НайтиПоКоду() во внешних решениях может быть единственным разумным выходом. Добавление констант или регистров сведений в типовую конфигурацию для хранения ссылок, ради внешней обработки, может создать больше проблем при обновлении, чем простое использование НайтиПоКоду() для стабильных кодов.НайтиПоКоду() может быть оценен как низкий.В то же время, важно помнить о риске: даже если коды стабильны годами, всегда есть вероятность, что пользователь или разработчик изменит их. Использование констант или регистров сведений для хранения таких ссылок в самой конфигурации (если есть возможность ее доработать) является наиболее надежным методом, так как пользователь будет изменять значение константы/регистра, а не код элемента, на который ссылается программа.
Помимо ПараметрыВыбора, существуют и другие мощные механизмы для управления списком значений, доступных пользователю.
СвязиПараметровВыбораСвойство СвязиПараметровВыбора элемента формы предназначено для динамического отбора значений на основе других реквизитов текущей формы. Например, если у нас есть поля "Контрагент" и "Договор", мы можем настроить связь так, чтобы при выборе Контрагента список Договоров автоматически фильтровался по выбранному Контрагенту.
ПараметрыВыбора, которые устанавливают статические условия, СвязиПараметровВыбора создают динамические условия, основанные на значениях других полей формы.ПараметрыВыбора и СвязиПараметровВыбора, то приоритет, как правило, будет у СвязиПараметровВыбора, если связанное поле заполнено.ОбработкаПолученияДанныхВыбораДля максимально гибкого и сложного управления списком выбора, особенно для перечислений, или в ситуациях, когда стандартные ПараметрыВыбора и СвязиПараметровВыбора не дают нужной функциональности, мы можем использовать процедуру ОбработкаПолученияДанныхВыбора(). Эта процедура находится в модуле менеджера объекта (для справочников, документов и т.д.) или модуля перечисления.
В этой процедуре мы можем полностью переопределить список доступных значений. Для этого необходимо:
СтандартнаяОбработка = Ложь, чтобы отменить стандартный механизм формирования списка.ДанныеВыбора СпискомЗначений или Массивом, содержащим только те элементы, которые должны быть доступны для выбора.Пример использования:
// В модуле менеджера справочника "Номенклатура"
Процедура ОбработкаПолученияДанныхВыбора(ДанныеВыбора, Параметры, СтандартнаяОбработка)
// Отменяем стандартную обработку
СтандартнаяОбработка = Ложь;
// Создаем новый СписокЗначений для вывода
СписокДоступныхТоваров = Новый СписокЗначений;
// Выполняем произвольный запрос или перебираем элементы,
// чтобы отобрать только нужные
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка,
| Номенклатура.Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Услуга = ЛОЖЬ
| И Номенклатура.ПометкаУдаления = ЛОЖЬ";
Результат = Запрос.Выполнить().Выгрузить();
Для Каждого СтрокаТЗ Из Результат Цикл
СписокДоступныхТоваров.Добавить(СтрокаТЗ.Ссылка, СтрокаТЗ.Наименование);
КонецЦикла;
// Передаем сформированный список в ДанныеВыбора
ДанныеВыбора = СписокДоступныхТоваров;
КонецПроцедуры
Этот метод предоставляет максимальную гибкость, позволяя формировать список выбора на основе любых условий, включая сложные запросы и логику.
Если программно установленные параметры выбора не работают или формируют неожиданный список, мы рекомендуем выполнить следующие шаги для диагностики:
ПриСозданииНаСервере, ПриОткрытии, а также в обработчиках событий, связанных с изменением других реквизитов формы), где могут быть установлены ПараметрыВыбора или СвязиПараметровВыбора. Убедитесь, что нет конфликтующих установок.Массив и ФиксированныйМассив, которые затем присваиваются свойству ПараметрыВыбора. Убедитесь, что ссылки на объекты корректны.ОбработкаПолученияДанныхВыбора, проверьте ее логику в модуле менеджера объекта.НачалоВыбораИзСписка с СтандартнаяОбработка = Ложь, чтобы отображался только ваш пользовательский список.Тщательная проверка этих аспектов поможет нам быстро локализовать и устранить причину некорректной работы параметров выбора.