При разработке интерфейсов на платформе 1С:Предприятие 8 часто возникает задача ограничить видимость определенных групп (папок) в справочнике. Если в обычном списке это решается простым отбором, то в режиме "Иерархический список" стандартные механизмы ведут себя специфически: скрытие родительской папки часто влечет за собой автоматическое скрытие всех вложенных элементов, либо нарушает структуру отображения. Проанализируем ситуацию и разберем все доступные методы решения этой задачи.
Рассмотрим, почему обычный Отбор в динамическом списке не всегда подходит. Когда пользователь включает режим просмотра "Иерархический список", платформа строит дерево связей на лету. Если мы установим отбор, исключающий конкретную папку, платформа может воспринять это двояко в зависимости от настроек:
Выясним, какие инструменты у нас есть, чтобы обойти эти ограничения.
Проанализируем метод, предложенный в обсуждении: использование механизма Условного оформления динамического списка. Этот способ хорош тем, что он не меняет состав выборки данных, а лишь управляет их визуальным представлением на клиенте.
Разберем по шагам, как настроить видимость через оформление:
Ссылка.ПометкаУдаления = Истина или Ссылка = &НежелательнаяПапка.Для более сложных случаев, когда нужно скрыть папку и все её содержимое (если иерархия глубокая), можно использовать проверку на вхождение в группу. Посмотрим на пример программной установки такого оформления:
// В процедуре ПриСозданииНаСервере
ЭлементОформления = Список.УсловноеОформление.Элементы.Добавить();
ЭлементОформления.Оформление.УстановитьЗначениеПараметра("Видимость", Ложь);
Условие = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
Условие.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Ссылка");
Условие.ВидСравнения = ВидСравненияКомпоновкиДанных.ВИерархии;
Условие.ПравоеЗначение = Параметры.СкрываемаяГруппа;
Важное замечание: Установка видимости в Ложь в условном оформлении иногда может оставлять "пустые строки" или влиять на работу полосы прокрутки. Проанализируем ситуацию: платформа передает данные строки на клиент, но не отрисовывает их. В современных версиях платформы 8.3 этот эффект минимизирован, но его следует учитывать.
Если нам нужно жестко исключить папки на уровне получения данных, разберем вариант с использованием произвольного запроса в динамическом списке. Это более производительный метод, так как лишние данные даже не попадут в выборку.
Рассмотрим пример запроса:
ВЫБРАТЬ
Спр.Ссылка КАК Ссылка,
Спр.Наименование КАК Наименование,
Спр.ЭтоГруппа КАК ЭтоГруппа
ИЗ
Справочник.Номенклатура КАК Спр
ГДЕ
НЕ Спр.Ссылка В (&МассивСкрытыхПапок)
И НЕ Спр.Родитель В (&МассивСкрытыхПапок)
Здесь кроется нюанс: если мы исключаем родителя, мы должны понимать, что произойдет с детьми. Если мы хотим скрыть только папку, но оставить её содержимое видимым в общем списке, нам придется отказаться от режима "Иерархический список" и перейти к обычному списку, либо программно переназначать родителя в запросе (что технически сложно и не рекомендуется).
Самый радикальный и надежный способ скрыть данные — это RLS (Record Level Security). Рассмотрим его преимущества:
Если бизнес-логика подразумевает, что пользователь в принципе не должен знать о существовании определенных разделов справочника, настроим соответствующую роль. В шаблоне ограничений для права "Чтение" пропишем условие, исключающее нужные группы.
Когда стандартный функционал динамического списка не позволяет добиться нужного визуального эффекта, профессионалы выбирают использование Дерева значений. Это позволяет полностью контролировать каждый узел.
Разберем этот подход подробнее:
ДеревоЗначений.Посмотрим на пример кода для рекурсивного заполнения такого дерева:
Процедура ЗаполнитьДерево(РодительСпр, СтрокаРодительДерева)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка,
| Номенклатура.Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Родитель = &Родитель
| И НЕ Номенклатура.Ссылка В (&СкрытыеГруппы)";
Запрос.УстановитьПараметр("Родитель", РодительСпр);
Запрос.УстановитьПараметр("СкрытыеГруппы", МассивСкрытыхГрупп);
Результат = Запрос.Выполнить().Выбрать();
Пока Результат.Следующий() Цикл
НоваяСтрока = СтрокаРодительДерева.Строки.Добавить();
НоваяСтрока.Наименование = Результат.Наименование;
НоваяСтрока.Ссылка = Результат.Ссылка;
// Если это группа, вызываем рекурсивно
Если Результат.Ссылка.ЭтоГруппа Тогда
ЗаполнитьДерево(Результат.Ссылка, НоваяСтрока);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Важно: При использовании дерева значений мы теряем возможности динамического списка, такие как "ленивая загрузка". Если в справочнике десятки тысяч элементов, дерево может работать медленно. В этом случае проанализируем возможность использования комбинированного метода.
Часто лучшим решением является разделение формы на две части:
Это позволяет избежать проблем с отображением иерархии в одном контроле и дает пользователю привычный интерфейс, напоминающий проводник Windows. Мы просто устанавливаем отбор в правом списке при активизации строки в левом дереве:
&НаКлиенте
Процедура ДеревоГруппПриАктивизацииСтроки(Элемент)
ТекущиеДанные = Элемент.ТекущиеДанные;
Если ТекущиеДанные <> Неопределено Тогда
// Устанавливаем отбор в динамическом списке элементов
ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбора(СписокЭлементов.Отбор,
"Родитель", ТекущиеДанные.Ссылка, Истина);
КонецЕсли;
КонецПроцедуры
В процессе обсуждения часто всплывает совет установить папку родителем самой себе через ОбменДанными.Загрузка = Истина. Категорически не рекомендуем использовать этот метод. Выясним причину:
Таким образом, для скрытия папок в иерархическом списке 1С наиболее корректными путями являются условное оформление (для простых задач визуализации) или комбинированный интерфейс "Дерево + Список" (для сложных интерфейсных решений с высокой нагрузкой).