Разработчики при проектировании интерфейсов в «1С:Предприятие» часто сталкиваются с задачей, когда пользователю необходимо предоставить возможность множественного выбора элементов справочника. Самый логичный и простой шаг — использовать для этого реквизит формы с типом СписокЗначений. Однако стандартное поведение платформы при работе с полями ввода такого типа таит в себе неочевидные нюансы, которые могут приводить к крайне неудобному поведению интерфейса: двойному открытию окон, некорректным отборам и «зависанию» фокуса ввода.
В этой статье мы подробно проанализируем, почему возникает конфликт стандартной обработки 1С с программными методами, и разберем четыре практических способа реализации удобного и корректного выбора элементов справочника с установленным отбором.
Прежде чем переходить к коду, давайте разберем саму механику возникновения проблемы, с которой часто сталкиваются начинающие разработчики.
Когда вы размещаете на управляемой форме поле ввода, связанное с реквизитом типа СписокЗначений, платформа автоматически назначает ему стандартный обработчик выбора. При нажатии на кнопку выбора (три точки) в таком поле система выполняет следующие действия:
Если разработчик пытается переопределить это поведение в событии НачалоВыбора поля ввода и программно открывает форму выбора справочника с помощью метода ОткрытьФорму, но при этом забывает отключить стандартные действия платформы, происходит конфликт интересов. Стандартная обработка продолжает выполняться параллельно с вашим кодом. В результате на экран выводится форма выбора справочника, а поверх нее (или под ней) сразу же открывается стандартное окно редактирования списка. Пользователь оказывается в замешательстве от хаотично всплывающих окон.
Выясним, какими способами можно элегантно решить эту задачу.
Для реализации этой задачи мы подготовили четыре пошаговых сценария — от самого простого использования стандартного диалога до профессионального кастомного подбора с полной отменой стандартного поведения платформы.
Этот способ отлично подходит для ситуаций, когда набор элементов для выбора относительно невелик и стабилен (например, список касс компании, складов или определенных видов документов). Мы можем полностью отказаться от открытия стандартной формы выбора справочника и использовать встроенный метод платформы ОтметитьЭлементы.
Давайте посмотрим на пример реализации этого алгоритма:
&НаКлиенте
Процедура ПодобратьИнформационныеБазы(Команда)
// Создаем временный список для интерактивного выбора пользователем
СписокВыбора = Новый СписокЗначений;
// Заполняем временный список на сервере только разрешенными элементами
ЗаполнитьДоступныеБазыНаСервере(СписокВыбора);
// Переносим пометки «Истина» для тех элементов, которые уже были выбраны ранее в нашем реквизите
Для Каждого ТекущийЭлемент Из СписокВыбора Цикл
Если Объект.БазаПриемник.НайтиПоЗначению(ТекущийЭлемент.Значение) <> Неопределено Тогда
ТекущийЭлемент.Пометка = Истина;
КонецЕсли;
КонецЦикла;
// Вызываем стандартное окно отметки элементов 1С
Если СписокВыбора.ОтметитьЭлементы("Выберите доступные базы приемники") Тогда
// Очищаем реквизит формы и переносим туда только те элементы, которые отметил пользователь
Объект.БазаПриемник.Очистить();
Для Каждого ВыбранныйЭлемент Из СписокВыбора Цикл
Если ВыбранныйЭлемент.Пометка Тогда
Объект.БазаПриемник.Добавить(ВыбранныйЭлемент.Значение);
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ЗаполнитьДоступныеБазыНаСервере(СписокВыбора)
// Выбираем только те базы, которые удовлетворяют нашему условию (например, активные)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ИнформационныеБазы.Ссылка КАК Ссылка
|ИЗ
| Справочник.ИнформационныеБазы КАК ИнформационныеБазы
|ГДЕ
| ИнформационныеБазы.ПометкаУдаления = ЛОЖЬ";
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
СписокВыбора.Добавить(Выборка.Ссылка);
КонецЦикла;
КонецПроцедуры
Преимущества: Простой код, отсутствие необходимости создавать собственные формы, очень быстрая работа при небольшом количестве элементов.
Недостатки: Не подходит для справочников с тысячами элементов (например, Номенклатура или Контрагенты), так как пользователю будет неудобно искать нужный элемент в плоском списке без иерархии и поиска.
Платформа 1С:Предприятие предоставляет мощный встроенный механизм ограничения выбора для списков значений. У объекта СписокЗначений существует стандартное свойство ДоступныеЗначения. Если мы заполним его массивом или списком разрешенных ссылок, платформа автоматически перестроит свое поведение.
При нажатии кнопки «Добавить» в стандартном окне редактирования списка значений платформа откроет форму выбора справочника, но принудительно наложит на нее жесткий отбор. Пользователь физически не сможет увидеть и выбрать элементы, не входящие в список доступных значений.
Рассмотрим по шагам реализацию данного подхода на сервере при создании формы:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Получаем массив только тех баз, которые нам разрешено выбирать
МассивРазрешенныхБаз = ПолучитьМассивДоступныхИнформационныхБаз();
// Создаем список значений для ограничения
ОграничивающийСписок = Новый СписокЗначений;
ОграничивающийСписок.ЗагрузитьЗначения(МассивРазрешенныхБаз);
// Устанавливаем свойство ДоступныеЗначения для реквизита нашей формы
Объект.БазаПриемник.ДоступныеЗначения = ОграничивающийСписок;
КонецПроцедуры
&НаСервере
Функция ПолучитьМассивДоступныхИнформационныхБаз()
// Здесь располагается ваша бизнес-логика получения отбора
Массив = Новый Массив;
// Пример заполнения демонстрационными данными:
// Массив.Добавить(Ссылка1);
// Массив.Добавить(Ссылка2);
Возврат Массив;
КонецФункции
При таком подходе вам вообще не нужно писать код в клиентских событиях НачалоВыбора или ОбработкаВыбора поля ввода! Система все сделает за вас в фоновом режиме, сохраняя стандартную эргономику платформы.
Если набор разрешенных к выбору элементов должен меняться динамически в процессе работы пользователя с формой (например, в зависимости от выбранной организации или даты), можно использовать программное управление свойством ПараметрыВыбора элемента формы.
Несмотря на то, что реквизит на форме имеет тип СписокЗначений, элемент формы (Поле ввода) позволяет транслировать параметры выбора непосредственно в форму списка, которая откроется при нажатии кнопки добавления. Разберем этот алгоритм:
&НаСервере
Процедура ОбновитьОтборДляПоляВыбора(МассивРазрешенныхБаз)
// Создаем параметр выбора "Отбор.Ссылка", передавая в него массив разрешенных значений
// Вид сравнения "В списке" подберется платформой автоматически
НовыйПараметр = Новый ПараметрВыбора("Отбор.Ссылка", МассивРазрешенныхБаз);
МассивПараметров = Новый Массив;
МассивПараметров.Добавить(НовыйПараметр);
// Устанавливаем параметры выбора непосредственно на элемент интерфейса (Поле ввода)
Элементы.БазаПриемник.ПараметрыВыбора = Новый ФиксированныйМассив(МассивПараметров);
КонецПроцедуры
Вызывать эту процедуру можно в любой момент жизни формы на сервере, когда меняются условия отбора баз-приемников. Платформа самостоятельно пробросит этот параметр в форму выбора справочника при её открытии из диалога редактирования списка.
Для продвинутых конфигураций часто требуется исключить стандартное «промежуточное» окно редактирования списка значений вообще. Оно заставляет пользователя совершать лишние клики (нажать кнопку выбора -> нажать «Добавить» -> выбрать элемент -> нажать «ОК»).
Гораздо приятнее для пользователя схема работы в один клик: нажимаем на кнопку выбора у поля ввода, сразу открывается полноценная форма выбора справочника с флагами множественного выбора и готовым отбором, пользователь отмечает нужные элементы, нажимает кнопку «Выбрать», и они моментально заполняют наш реквизит.
Давайте подробно разберем по шагам, как запрограммировать такой интерфейс.
Шаг 1. Переопределяем событие начала выбора
В модуле управляемой формы находим событие НачалоВыбора для нашего элемента формы БазаПриемник. Отменяем стандартную обработку и программно вызываем нужную форму с нужными настройками:
&НаКлиенте
Процедура БазаПриемникНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
// Шаг 1.1: Отменяем запуск стандартного окна редактирования списка
СтандартнаяОбработка = Ложь;
// Шаг 1.2: Получаем актуальный массив разрешенных к выбору элементов с сервера
МассивРазрешенныхБаз = ПолучитьСписокДоступныхИнформационныхБазНаСервере();
// Шаг 1.3: Формируем параметры открытия формы выбора справочника
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("МножественныйВыбор", Истина);
ПараметрыФормы.Вставить("РежимВыбора", Истина);
// Шаг 1.4: Накладываем жесткий отбор на динамический список формы выбора через фиксированные настройки
НастройкиКД = Новый НастройкиКомпоновкиДанных;
ЭлементОтбора = НастройкиКД.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Ссылка");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке;
ЭлементОтбора.ПравоеЗначение = МассивРазрешенныхБаз;
ЭлементОтбора.Использование = Истина;
ПараметрыФормы.Вставить("ФиксированныеНастройки", НастройкиКД);
// Шаг 1.5: Открываем форму, указывая текущий элемент формы в качестве владельца для отлова события выбора
ОткрытьФорму("Справочник.ИнформационныеБазы.ФормаВыбора", ПараметрыФормы, Элемент);
КонецПроцедуры
Шаг 2. Обрабатываем результат выбора
Теперь нам необходимо перехватить то, что выбрал пользователь в открывшейся форме выбора. Для этого у элемента формы БазаПриемник создаем обработчик события ОбработкаВыбора:
&НаКлиенте
Процедура БазаПриемникОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
// Шаг 2.1: Блокируем стандартную запись значения платформой
СтандартнаяОбработка = Ложь;
// Шаг 2.2: Очищаем текущий список значений реквизита
Объект.БазаПриемник.Очистить();
// Шаг 2.3: Наполняем его элементами, вернувшимися из формы выбора справочника
Если ТипЗнч(ВыбранноеЗначение) = Тип("Массив") Тогда
// Сюда мы попадаем, если пользователь выбрал несколько элементов подряд
Для Каждого ТекущаяСсылка Из ВыбранноеЗначение Цикл
Объект.БазаПриемник.Добавить(ТекущаяСсылка);
КонецЦикла;
ИначеЕсли ЗначениеЗаполнено(ВыбранноеЗначение) Тогда
// Сюда мы попадаем, если пользователь выбрал ровно один элемент
Объект.БазаПриемник.Добавить(ВыбранноеЗначение);
КонецЕсли;
КонецПроцедуры
Этот способ по праву считается эталонным с точки зрения UI/UX-дизайна в системе 1С:Предприятие 8, поскольку он не перегружает пользователя лишними техническими окнами редактирования коллекций и позволяет сразу же перейти к выбору данных.
Мы детально рассмотрели проблему двойного открытия окон и изучили различные способы реализации выбора элементов с установкой отбора для реквизитов типа СписокЗначений.
При выборе конкретного метода мы рекомендуем руководствоваться следующими правилами: