При разработке на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с задачей: нужно запретить пользователю выбирать любые элементы справочника, ограничив список только определенным набором. Казалось бы, достаточно использовать событие НачалоВыбора, но здесь начинающих разработчиков подстерегает ловушка. В управляемых формах поведение этого события зависит от того, каким именно образом пользователь инициирует выбор. Рассмотрим подробнее, почему стандартные методы могут не срабатывать и как реализовать фильтрацию правильно.
Проанализируем ситуацию, описанную участниками форума. Пользователь нажимает на "стрелочку" (выпадающий список) в поле ввода, но программный обработчик НачалоВыбора не вызывается. Почему так происходит? Выясним причину: в 1С существуют две принципиально разные кнопки в поле ввода:
НачалоВыбора.НачалоВыбораИзСписка.Если в свойствах элемента формы стоит автоматическое определение кнопок, система часто подменяет одну другой в зависимости от типа данных и настроек. Поэтому первым делом разберем, как сделать так, чтобы наше ограничение работало во всех случаях.
Если список доступных элементов невелик и заранее известен, можно перевести поле в режим работы "Combo Box". Для этого в конфигураторе или программно установим свойство РежимВыбораИзСписка в значение Истина. Посмотрим на логику работы в этом режиме: поле перестает открывать стандартную форму справочника и начинает работать исключительно с фиксированным списком.
Рассмотрим пример программного заполнения такого списка:
&НаКлиенте
Процедура ТекКонтрагентНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь; // Отключаем стандартный поиск в базе
ДанныеДляВыбора = ТекКонтрагентНачалоВыбораНаСервере();
Элемент.СписокВыбора.ЗагрузитьЗначения(ДанныеДляВыбора.ВыгрузитьЗначения());
КонецПроцедуры
&НаСервереБезКонтекста
Функция ТекКонтрагентНачалоВыбораНаСервере()
Список = Новый СписокЗначений;
Список.Добавить(Справочники.Контрагенты.НайтиПоКоду("000000030"));
Список.Добавить(Справочники.Контрагенты.НайтиПоКоду("000000069"));
Возврат Список;
КонецФункции
Если нам все же нужно открывать форму выбора, но с наложенным фильтром, правильнее всего будет использовать параметр ФиксированныеНастройки. Разберем по шагам, как это реализовать в событии НачалоВыбора, чтобы пользователь видел в форме только нужные элементы.
Проанализируем следующий алгоритм:
НачалоВыбора.СтандартнаяОбработка = Ложь.ВСписке.Пример реализации кода:
&НаКлиенте
Процедура НоменклатураНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// Получаем список разрешенных элементов с сервера
СписокРазрешенных = ПолучитьСписокДоступнойНоменклатурыНаСервере();
// Формируем структуру параметров для формы выбора
ПараметрыОтбора = Новый Структура;
НастройкиОтбора = Новый НастройкиКомпоновкиДанных;
ЭлементОтбора = НастройкиОтбора.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Ссылка");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке;
ЭлементОтбора.ПравоеЗначение = СписокРазрешенных;
ЭлементОтбора.Использование = Истина;
ПараметрыОтбора.Вставить("ФиксированныеНастройки", НастройкиОтбора);
// Открываем форму выбора справочника с наложенным фильтром
ОткрытьФорму("Справочник.Номенклатура.ФормаВыбора", ПараметрыОтбора, Элемент);
КонецПроцедуры
Иногда программисты забывают о самом простом и эффективном способе — использовании свойства ПараметрыВыбора (ChoiceParameters). Это работает без написания сложного кода в модуле формы. Если условие фильтрации статичное (например, выбирать только тех контрагентов, у которых стоит флаг Активен), мы можем настроить это прямо в конфигураторе в свойствах реквизита.
Если же фильтр должен меняться динамически, мы можем управлять этим свойством программно. Рассмотрим, как это сделать:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Ограничиваем выбор только папкой "Оптовые покупатели"
НовыйПараметр = Новый ПараметрВыбора("Отбор.Родитель", Справочники.Контрагенты.НайтиПоНаименованию("Оптовики"));
МассивПараметров = Новый Массив;
МассивПараметров.Добавить(НовыйПараметр);
Элементы.Контрагент.ПараметрыВыбора = Новый ФиксированныйМассив(МассивПараметров);
КонецПроцедуры
Проанализируем ситуацию: вы настроили все фильтры, но при нажатии на поле пользователь все равно видит старые, "запрещенные" элементы. Это происходит из-за механизма Истории выбора. Система запоминает, что пользователь выбирал ранее, и предлагает это в первую очередь, игнорируя новые программные фильтры.
Чтобы очистить этот список и заставить систему всегда применять ваши правила, необходимо у элемента формы установить свойство ИсторияВыбораПриВводе в значение Не использовать. Это критически важный момент для обеспечения чистоты интерфейса.
Если вам нужно, чтобы фильтрация работала глобально во всей системе (не только в одной форме, а везде, где выбирается этот справочник, включая автоподбор при вводе текста), рекомендуется использовать событие ОбработкаПолученияДанныхВыбора в модуле менеджера справочника. Это наиболее "продвинутый" способ, так как он работает на уровне ядра платформы. В этом событии вы можете подменить стандартный запрос системы к базе данных своим собственным, вернув только нужный массив ссылок в параметре ДанныеВыбора.
Подведем итог: выбор метода зависит от задачи. Для простых фильтров используйте ПараметрыВыбора. Для сложных условий в конкретной форме — НачалоВыбора с подменой формы. Для создания выпадающих списков — РежимВыбораИзСписка. И всегда помните про отключение истории выбора, чтобы ваши настройки не конфликтовали с кэшем пользователя.